1
2
3
4
5 package carchive_test
6
7 import (
8 "bufio"
9 "bytes"
10 "debug/elf"
11 "flag"
12 "fmt"
13 "io"
14 "log"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "regexp"
19 "runtime"
20 "strconv"
21 "strings"
22 "syscall"
23 "testing"
24 "time"
25 "unicode"
26 )
27
28
29 var bin []string
30
31
32 var cc []string
33
34
35 var exeSuffix string
36
37 var GOOS, GOARCH, GOPATH string
38 var libgodir string
39
40 var testWork bool
41
42 func TestMain(m *testing.M) {
43 flag.BoolVar(&testWork, "testwork", false, "if true, log and preserve the test's temporary working directory")
44 flag.Parse()
45 if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
46 fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
47 os.Exit(0)
48 }
49 log.SetFlags(log.Lshortfile)
50 os.Exit(testMain(m))
51 }
52
53 func testMain(m *testing.M) int {
54
55
56 var err error
57 GOPATH, err = os.MkdirTemp("", "carchive_test")
58 if err != nil {
59 log.Panic(err)
60 }
61 if testWork {
62 log.Println(GOPATH)
63 } else {
64 defer os.RemoveAll(GOPATH)
65 }
66 os.Setenv("GOPATH", GOPATH)
67
68
69
70 modRoot := filepath.Join(GOPATH, "src", "testcarchive")
71 if err := overlayDir(modRoot, "testdata"); err != nil {
72 log.Panic(err)
73 }
74 if err := os.Chdir(modRoot); err != nil {
75 log.Panic(err)
76 }
77 os.Setenv("PWD", modRoot)
78 if err := os.WriteFile("go.mod", []byte("module testcarchive\n"), 0666); err != nil {
79 log.Panic(err)
80 }
81
82 GOOS = goEnv("GOOS")
83 GOARCH = goEnv("GOARCH")
84 bin = cmdToRun("./testp")
85
86 ccOut := goEnv("CC")
87 cc = []string{string(ccOut)}
88
89 out := goEnv("GOGCCFLAGS")
90 quote := '\000'
91 start := 0
92 lastSpace := true
93 backslash := false
94 s := string(out)
95 for i, c := range s {
96 if quote == '\000' && unicode.IsSpace(c) {
97 if !lastSpace {
98 cc = append(cc, s[start:i])
99 lastSpace = true
100 }
101 } else {
102 if lastSpace {
103 start = i
104 lastSpace = false
105 }
106 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
107 quote = c
108 backslash = false
109 } else if !backslash && quote == c {
110 quote = '\000'
111 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
112 backslash = true
113 } else {
114 backslash = false
115 }
116 }
117 }
118 if !lastSpace {
119 cc = append(cc, s[start:])
120 }
121
122 if GOOS == "aix" {
123
124
125 cc = append(cc, "-Wl,-bnoobjreorder")
126 }
127 libbase := GOOS + "_" + GOARCH
128 if runtime.Compiler == "gccgo" {
129 libbase = "gccgo_" + libgodir + "_fPIC"
130 } else {
131 switch GOOS {
132 case "darwin", "ios":
133 if GOARCH == "arm64" {
134 libbase += "_shared"
135 }
136 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris", "illumos":
137 libbase += "_shared"
138 }
139 }
140 libgodir = filepath.Join(GOPATH, "pkg", libbase, "testcarchive")
141 cc = append(cc, "-I", libgodir)
142
143
144 cc = cc[:len(cc):len(cc)]
145
146 if GOOS == "windows" {
147 exeSuffix = ".exe"
148 }
149
150 return m.Run()
151 }
152
153 func goEnv(key string) string {
154 out, err := exec.Command("go", "env", key).Output()
155 if err != nil {
156 if ee, ok := err.(*exec.ExitError); ok {
157 fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
158 }
159 log.Panicf("go env %s failed:\n%s\n", key, err)
160 }
161 return strings.TrimSpace(string(out))
162 }
163
164 func cmdToRun(name string) []string {
165 execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
166 executor, err := exec.LookPath(execScript)
167 if err != nil {
168 return []string{name}
169 }
170 return []string{executor, name}
171 }
172
173
174
175
176
177 func genHeader(t *testing.T, header, dir string) {
178 t.Helper()
179
180
181
182
183 objDir, err := os.MkdirTemp(GOPATH, "_obj")
184 if err != nil {
185 t.Fatal(err)
186 }
187 defer os.RemoveAll(objDir)
188
189 files, err := filepath.Glob(filepath.Join(dir, "*.go"))
190 if err != nil {
191 t.Fatal(err)
192 }
193
194 cmd := exec.Command("go", "tool", "cgo",
195 "-objdir", objDir,
196 "-exportheader", header)
197 cmd.Args = append(cmd.Args, files...)
198 t.Log(cmd.Args)
199 if out, err := cmd.CombinedOutput(); err != nil {
200 t.Logf("%s", out)
201 t.Fatal(err)
202 }
203 }
204
205 func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
206 t.Helper()
207 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
208 t.Log(buildcmd)
209 if out, err := cmd.CombinedOutput(); err != nil {
210 t.Logf("%s", out)
211 t.Fatal(err)
212 }
213 if !testWork {
214 defer func() {
215 os.Remove(libgoa)
216 os.Remove(libgoh)
217 }()
218 }
219
220 ccArgs := append(cc, "-o", exe, "main.c")
221 if GOOS == "windows" {
222 ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
223 } else {
224 ccArgs = append(ccArgs, "main_unix.c", libgoa)
225 }
226 if runtime.Compiler == "gccgo" {
227 ccArgs = append(ccArgs, "-lgo")
228 }
229 t.Log(ccArgs)
230 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
231 t.Logf("%s", out)
232 t.Fatal(err)
233 }
234 if !testWork {
235 defer os.Remove(exe)
236 }
237
238 binArgs := append(cmdToRun(exe), "arg1", "arg2")
239 cmd = exec.Command(binArgs[0], binArgs[1:]...)
240 if runtime.Compiler == "gccgo" {
241 cmd.Env = append(os.Environ(), "GCCGO=1")
242 }
243 if out, err := cmd.CombinedOutput(); err != nil {
244 t.Logf("%s", out)
245 t.Fatal(err)
246 }
247
248 checkLineComments(t, libgoh)
249 }
250
251 var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
252
253
254
255
256
257
258 func checkLineComments(t *testing.T, hdrname string) {
259 hdr, err := os.ReadFile(hdrname)
260 if err != nil {
261 if !os.IsNotExist(err) {
262 t.Error(err)
263 }
264 return
265 }
266 if line := badLineRegexp.Find(hdr); line != nil {
267 t.Errorf("bad #line directive with absolute path in %s: %q", hdrname, line)
268 }
269 }
270
271
272
273 func checkArchive(t *testing.T, arname string) {
274 t.Helper()
275
276 switch GOOS {
277 case "aix", "darwin", "ios", "windows":
278
279 if _, err := os.Stat(arname); err != nil {
280 t.Errorf("archive %s does not exist: %v", arname, err)
281 }
282 default:
283 checkELFArchive(t, arname)
284 }
285 }
286
287
288 func checkELFArchive(t *testing.T, arname string) {
289 t.Helper()
290
291 f, err := os.Open(arname)
292 if err != nil {
293 t.Errorf("archive %s does not exist: %v", arname, err)
294 return
295 }
296 defer f.Close()
297
298
299 const (
300 magic = "!<arch>\n"
301 fmag = "`\n"
302
303 namelen = 16
304 datelen = 12
305 uidlen = 6
306 gidlen = 6
307 modelen = 8
308 sizelen = 10
309 fmaglen = 2
310 hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
311 )
312
313 type arhdr struct {
314 name string
315 date string
316 uid string
317 gid string
318 mode string
319 size string
320 fmag string
321 }
322
323 var magbuf [len(magic)]byte
324 if _, err := io.ReadFull(f, magbuf[:]); err != nil {
325 t.Errorf("%s: archive too short", arname)
326 return
327 }
328 if string(magbuf[:]) != magic {
329 t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
330 }
331
332 off := int64(len(magic))
333 for {
334 if off&1 != 0 {
335 var b [1]byte
336 if _, err := f.Read(b[:]); err != nil {
337 if err == io.EOF {
338 break
339 }
340 t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
341 }
342 off++
343 }
344
345 var hdrbuf [hdrlen]byte
346 if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
347 if err == io.EOF {
348 break
349 }
350 t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
351 return
352 }
353
354 var hdr arhdr
355 hdrslice := hdrbuf[:]
356 set := func(len int, ps *string) {
357 *ps = string(bytes.TrimSpace(hdrslice[:len]))
358 hdrslice = hdrslice[len:]
359 }
360 set(namelen, &hdr.name)
361 set(datelen, &hdr.date)
362 set(uidlen, &hdr.uid)
363 set(gidlen, &hdr.gid)
364 set(modelen, &hdr.mode)
365 set(sizelen, &hdr.size)
366 hdr.fmag = string(hdrslice[:fmaglen])
367 hdrslice = hdrslice[fmaglen:]
368 if len(hdrslice) != 0 {
369 t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
370 }
371
372 if hdr.fmag != fmag {
373 t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
374 return
375 }
376
377 size, err := strconv.ParseInt(hdr.size, 10, 64)
378 if err != nil {
379 t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
380 return
381 }
382
383 off += hdrlen
384
385 switch hdr.name {
386 case "__.SYMDEF", "/", "/SYM64/":
387
388 case "//", "ARFILENAMES/":
389
390 default:
391
392 checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
393 }
394
395 off += size
396 if _, err := f.Seek(off, os.SEEK_SET); err != nil {
397 t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
398 }
399 }
400 }
401
402
403 func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
404 t.Helper()
405
406 ef, err := elf.NewFile(obj)
407 if err != nil {
408 t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
409 return
410 }
411 defer ef.Close()
412
413
414 for _, sec := range ef.Sections {
415 want := elf.SHT_NULL
416 switch sec.Name {
417 case ".text", ".data":
418 want = elf.SHT_PROGBITS
419 case ".bss":
420 want = elf.SHT_NOBITS
421 case ".symtab":
422 want = elf.SHT_SYMTAB
423 case ".strtab":
424 want = elf.SHT_STRTAB
425 case ".init_array":
426 want = elf.SHT_INIT_ARRAY
427 case ".fini_array":
428 want = elf.SHT_FINI_ARRAY
429 case ".preinit_array":
430 want = elf.SHT_PREINIT_ARRAY
431 }
432 if want != elf.SHT_NULL && sec.Type != want {
433 t.Errorf("%s: incorrect section type in elf file at %d for section %q: got %v want %v", arname, off, sec.Name, sec.Type, want)
434 }
435 }
436 }
437
438 func TestInstall(t *testing.T) {
439 if !testWork {
440 defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
441 }
442
443 libgoa := "libgo.a"
444 if runtime.Compiler == "gccgo" {
445 libgoa = "liblibgo.a"
446 }
447
448
449
450
451
452
453
454 genHeader(t, "p.h", "./p")
455
456 testInstall(t, "./testp1"+exeSuffix,
457 filepath.Join(libgodir, libgoa),
458 filepath.Join(libgodir, "libgo.h"),
459 "go", "install", "-buildmode=c-archive", "./libgo")
460
461
462
463 testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
464 "go", "build", "-buildmode=c-archive", filepath.Join(".", "libgo", "libgo.go"))
465
466 testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
467 "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "./libgo")
468 }
469
470 func TestEarlySignalHandler(t *testing.T) {
471 switch GOOS {
472 case "darwin", "ios":
473 switch GOARCH {
474 case "arm64":
475 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
476 }
477 case "windows":
478 t.Skip("skipping signal test on Windows")
479 }
480
481 if !testWork {
482 defer func() {
483 os.Remove("libgo2.a")
484 os.Remove("libgo2.h")
485 os.Remove("testp" + exeSuffix)
486 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
487 }()
488 }
489
490 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
491 if out, err := cmd.CombinedOutput(); err != nil {
492 t.Logf("%s", out)
493 t.Fatal(err)
494 }
495 checkLineComments(t, "libgo2.h")
496 checkArchive(t, "libgo2.a")
497
498 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
499 if runtime.Compiler == "gccgo" {
500 ccArgs = append(ccArgs, "-lgo")
501 }
502 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
503 t.Logf("%s", out)
504 t.Fatal(err)
505 }
506
507 darwin := "0"
508 if runtime.GOOS == "darwin" {
509 darwin = "1"
510 }
511 cmd = exec.Command(bin[0], append(bin[1:], darwin)...)
512
513 if out, err := cmd.CombinedOutput(); err != nil {
514 t.Logf("%s", out)
515 t.Fatal(err)
516 }
517 }
518
519 func TestSignalForwarding(t *testing.T) {
520 checkSignalForwardingTest(t)
521
522 if !testWork {
523 defer func() {
524 os.Remove("libgo2.a")
525 os.Remove("libgo2.h")
526 os.Remove("testp" + exeSuffix)
527 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
528 }()
529 }
530
531 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
532 if out, err := cmd.CombinedOutput(); err != nil {
533 t.Logf("%s", out)
534 t.Fatal(err)
535 }
536 checkLineComments(t, "libgo2.h")
537 checkArchive(t, "libgo2.a")
538
539 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
540 if runtime.Compiler == "gccgo" {
541 ccArgs = append(ccArgs, "-lgo")
542 }
543 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
544 t.Logf("%s", out)
545 t.Fatal(err)
546 }
547
548 cmd = exec.Command(bin[0], append(bin[1:], "1")...)
549
550 out, err := cmd.CombinedOutput()
551 t.Logf("%v\n%s", cmd.Args, out)
552 expectSignal(t, err, syscall.SIGSEGV)
553
554
555 if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
556
557 cmd = exec.Command(bin[0], append(bin[1:], "3")...)
558
559 out, err = cmd.CombinedOutput()
560 if len(out) > 0 {
561 t.Logf("%s", out)
562 }
563 expectSignal(t, err, syscall.SIGPIPE)
564 }
565 }
566
567 func TestSignalForwardingExternal(t *testing.T) {
568 if GOOS == "freebsd" || GOOS == "aix" {
569 t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
570 } else if GOOS == "darwin" && GOARCH == "amd64" {
571 t.Skipf("skipping on %s/%s: runtime does not permit SI_USER SIGSEGV", GOOS, GOARCH)
572 }
573 checkSignalForwardingTest(t)
574
575 if !testWork {
576 defer func() {
577 os.Remove("libgo2.a")
578 os.Remove("libgo2.h")
579 os.Remove("testp" + exeSuffix)
580 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
581 }()
582 }
583
584 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
585 if out, err := cmd.CombinedOutput(); err != nil {
586 t.Logf("%s", out)
587 t.Fatal(err)
588 }
589 checkLineComments(t, "libgo2.h")
590 checkArchive(t, "libgo2.a")
591
592 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
593 if runtime.Compiler == "gccgo" {
594 ccArgs = append(ccArgs, "-lgo")
595 }
596 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
597 t.Logf("%s", out)
598 t.Fatal(err)
599 }
600
601
602
603
604
605
606
607
608
609
610 const tries = 20
611 for i := 0; i < tries; i++ {
612 cmd = exec.Command(bin[0], append(bin[1:], "2")...)
613
614 stderr, err := cmd.StderrPipe()
615 if err != nil {
616 t.Fatal(err)
617 }
618 defer stderr.Close()
619
620 r := bufio.NewReader(stderr)
621
622 err = cmd.Start()
623
624 if err != nil {
625 t.Fatal(err)
626 }
627
628
629 ok, err := r.ReadString('\n')
630
631
632 if err != nil || ok != "OK\n" {
633 t.Fatalf("Did not receive OK signal")
634 }
635
636
637 time.Sleep(time.Millisecond)
638
639 cmd.Process.Signal(syscall.SIGSEGV)
640
641 err = cmd.Wait()
642
643 if err == nil {
644 continue
645 }
646
647 if expectSignal(t, err, syscall.SIGSEGV) {
648 return
649 }
650 }
651
652 t.Errorf("program succeeded unexpectedly %d times", tries)
653 }
654
655
656
657 func checkSignalForwardingTest(t *testing.T) {
658 switch GOOS {
659 case "darwin", "ios":
660 switch GOARCH {
661 case "arm64":
662 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
663 }
664 case "windows":
665 t.Skip("skipping signal test on Windows")
666 }
667 }
668
669
670
671
672 func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
673 if err == nil {
674 t.Error("test program succeeded unexpectedly")
675 } else if ee, ok := err.(*exec.ExitError); !ok {
676 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
677 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
678 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
679 } else if !ws.Signaled() || ws.Signal() != sig {
680 t.Errorf("got %v; expected signal %v", ee, sig)
681 } else {
682 return true
683 }
684 return false
685 }
686
687 func TestOsSignal(t *testing.T) {
688 switch GOOS {
689 case "windows":
690 t.Skip("skipping signal test on Windows")
691 }
692
693 if !testWork {
694 defer func() {
695 os.Remove("libgo3.a")
696 os.Remove("libgo3.h")
697 os.Remove("testp" + exeSuffix)
698 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
699 }()
700 }
701
702 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "./libgo3")
703 if out, err := cmd.CombinedOutput(); err != nil {
704 t.Logf("%s", out)
705 t.Fatal(err)
706 }
707 checkLineComments(t, "libgo3.h")
708 checkArchive(t, "libgo3.a")
709
710 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
711 if runtime.Compiler == "gccgo" {
712 ccArgs = append(ccArgs, "-lgo")
713 }
714 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
715 t.Logf("%s", out)
716 t.Fatal(err)
717 }
718
719 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
720 t.Logf("%s", out)
721 t.Fatal(err)
722 }
723 }
724
725 func TestSigaltstack(t *testing.T) {
726 switch GOOS {
727 case "windows":
728 t.Skip("skipping signal test on Windows")
729 }
730
731 if !testWork {
732 defer func() {
733 os.Remove("libgo4.a")
734 os.Remove("libgo4.h")
735 os.Remove("testp" + exeSuffix)
736 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
737 }()
738 }
739
740 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "./libgo4")
741 if out, err := cmd.CombinedOutput(); err != nil {
742 t.Logf("%s", out)
743 t.Fatal(err)
744 }
745 checkLineComments(t, "libgo4.h")
746 checkArchive(t, "libgo4.a")
747
748 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
749 if runtime.Compiler == "gccgo" {
750 ccArgs = append(ccArgs, "-lgo")
751 }
752 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
753 t.Logf("%s", out)
754 t.Fatal(err)
755 }
756
757 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
758 t.Logf("%s", out)
759 t.Fatal(err)
760 }
761 }
762
763 const testar = `#!/usr/bin/env bash
764 while [[ $1 == -* ]] >/dev/null; do
765 shift
766 done
767 echo "testar" > $1
768 echo "testar" > PWD/testar.ran
769 `
770
771 func TestExtar(t *testing.T) {
772 switch GOOS {
773 case "windows":
774 t.Skip("skipping signal test on Windows")
775 }
776 if runtime.Compiler == "gccgo" {
777 t.Skip("skipping -extar test when using gccgo")
778 }
779 if runtime.GOOS == "ios" {
780 t.Skip("shell scripts are not executable on iOS hosts")
781 }
782
783 if !testWork {
784 defer func() {
785 os.Remove("libgo4.a")
786 os.Remove("libgo4.h")
787 os.Remove("testar")
788 os.Remove("testar.ran")
789 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
790 }()
791 }
792
793 os.Remove("testar")
794 dir, err := os.Getwd()
795 if err != nil {
796 t.Fatal(err)
797 }
798 s := strings.Replace(testar, "PWD", dir, 1)
799 if err := os.WriteFile("testar", []byte(s), 0777); err != nil {
800 t.Fatal(err)
801 }
802
803 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "./libgo4")
804 if out, err := cmd.CombinedOutput(); err != nil {
805 t.Logf("%s", out)
806 t.Fatal(err)
807 }
808 checkLineComments(t, "libgo4.h")
809
810 if _, err := os.Stat("testar.ran"); err != nil {
811 if os.IsNotExist(err) {
812 t.Error("testar does not exist after go build")
813 } else {
814 t.Errorf("error checking testar: %v", err)
815 }
816 }
817 }
818
819 func TestPIE(t *testing.T) {
820 switch GOOS {
821 case "windows", "darwin", "ios", "plan9":
822 t.Skipf("skipping PIE test on %s", GOOS)
823 }
824
825 if !testWork {
826 defer func() {
827 os.Remove("testp" + exeSuffix)
828 os.RemoveAll(filepath.Join(GOPATH, "pkg"))
829 }()
830 }
831
832
833
834
835
836
837
838 genHeader(t, "p.h", "./p")
839
840 cmd := exec.Command("go", "install", "-buildmode=c-archive", "./libgo")
841 if out, err := cmd.CombinedOutput(); err != nil {
842 t.Logf("%s", out)
843 t.Fatal(err)
844 }
845
846 libgoa := "libgo.a"
847 if runtime.Compiler == "gccgo" {
848 libgoa = "liblibgo.a"
849 }
850
851 ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join(libgodir, libgoa))
852 if runtime.Compiler == "gccgo" {
853 ccArgs = append(ccArgs, "-lgo")
854 }
855 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
856 t.Logf("%s", out)
857 t.Fatal(err)
858 }
859
860 binArgs := append(bin, "arg1", "arg2")
861 cmd = exec.Command(binArgs[0], binArgs[1:]...)
862 if runtime.Compiler == "gccgo" {
863 cmd.Env = append(os.Environ(), "GCCGO=1")
864 }
865 if out, err := cmd.CombinedOutput(); err != nil {
866 t.Logf("%s", out)
867 t.Fatal(err)
868 }
869
870 if GOOS != "aix" {
871 f, err := elf.Open("testp" + exeSuffix)
872 if err != nil {
873 t.Fatal("elf.Open failed: ", err)
874 }
875 defer f.Close()
876 if hasDynTag(t, f, elf.DT_TEXTREL) {
877 t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
878 }
879 }
880 }
881
882 func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
883 ds := f.SectionByType(elf.SHT_DYNAMIC)
884 if ds == nil {
885 t.Error("no SHT_DYNAMIC section")
886 return false
887 }
888 d, err := ds.Data()
889 if err != nil {
890 t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
891 return false
892 }
893 for len(d) > 0 {
894 var t elf.DynTag
895 switch f.Class {
896 case elf.ELFCLASS32:
897 t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
898 d = d[8:]
899 case elf.ELFCLASS64:
900 t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
901 d = d[16:]
902 }
903 if t == tag {
904 return true
905 }
906 }
907 return false
908 }
909
910 func TestSIGPROF(t *testing.T) {
911 switch GOOS {
912 case "windows", "plan9":
913 t.Skipf("skipping SIGPROF test on %s", GOOS)
914 case "darwin", "ios":
915 t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS)
916 }
917
918 t.Parallel()
919
920 if !testWork {
921 defer func() {
922 os.Remove("testp6" + exeSuffix)
923 os.Remove("libgo6.a")
924 os.Remove("libgo6.h")
925 }()
926 }
927
928 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
929 out, err := cmd.CombinedOutput()
930 t.Logf("%v\n%s", cmd.Args, out)
931 if err != nil {
932 t.Fatal(err)
933 }
934 checkLineComments(t, "libgo6.h")
935 checkArchive(t, "libgo6.a")
936
937 ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
938 if runtime.Compiler == "gccgo" {
939 ccArgs = append(ccArgs, "-lgo")
940 }
941 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
942 t.Logf("%v\n%s", ccArgs, out)
943 if err != nil {
944 t.Fatal(err)
945 }
946
947 argv := cmdToRun("./testp6")
948 cmd = exec.Command(argv[0], argv[1:]...)
949 out, err = cmd.CombinedOutput()
950 t.Logf("%v\n%s", argv, out)
951 if err != nil {
952 t.Fatal(err)
953 }
954 }
955
956
957
958
959
960
961
962 func TestCompileWithoutShared(t *testing.T) {
963
964 checkSignalForwardingTest(t)
965
966 if !testWork {
967 defer func() {
968 os.Remove("libgo2.a")
969 os.Remove("libgo2.h")
970 }()
971 }
972
973 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
974 out, err := cmd.CombinedOutput()
975 t.Logf("%v\n%s", cmd.Args, out)
976 if err != nil {
977 t.Fatal(err)
978 }
979 checkLineComments(t, "libgo2.h")
980 checkArchive(t, "libgo2.a")
981
982 exe := "./testnoshared" + exeSuffix
983
984
985
986 ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a")
987 if runtime.Compiler == "gccgo" {
988 ccArgs = append(ccArgs, "-lgo")
989 }
990 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
991 t.Logf("%v\n%s", ccArgs, out)
992
993
994 if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
995 ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
996 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
997 t.Logf("%v\n%s", ccArgs, out)
998 }
999
1000
1001 if err != nil && bytes.Contains(out, []byte("unrecognized")) {
1002 ccArgs = append(cc, "-o", exe, "main5.c", "libgo2.a")
1003 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1004 t.Logf("%v\n%s", ccArgs, out)
1005 }
1006 if err != nil {
1007 t.Fatal(err)
1008 }
1009 if !testWork {
1010 defer os.Remove(exe)
1011 }
1012
1013 binArgs := append(cmdToRun(exe), "1")
1014 out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
1015 t.Logf("%v\n%s", binArgs, out)
1016 expectSignal(t, err, syscall.SIGSEGV)
1017
1018
1019 if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
1020 binArgs := append(cmdToRun(exe), "3")
1021 out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
1022 t.Logf("%v\n%s", binArgs, out)
1023 expectSignal(t, err, syscall.SIGPIPE)
1024 }
1025 }
1026
1027
1028 func TestCachedInstall(t *testing.T) {
1029 if !testWork {
1030 defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
1031 }
1032
1033 h := filepath.Join(libgodir, "libgo.h")
1034
1035 buildcmd := []string{"go", "install", "-buildmode=c-archive", "./libgo"}
1036
1037 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
1038 t.Log(buildcmd)
1039 if out, err := cmd.CombinedOutput(); err != nil {
1040 t.Logf("%s", out)
1041 t.Fatal(err)
1042 }
1043
1044 if _, err := os.Stat(h); err != nil {
1045 t.Errorf("libgo.h not installed: %v", err)
1046 }
1047
1048 if err := os.Remove(h); err != nil {
1049 t.Fatal(err)
1050 }
1051
1052 cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
1053 t.Log(buildcmd)
1054 if out, err := cmd.CombinedOutput(); err != nil {
1055 t.Logf("%s", out)
1056 t.Fatal(err)
1057 }
1058
1059 if _, err := os.Stat(h); err != nil {
1060 t.Errorf("libgo.h not installed in second run: %v", err)
1061 }
1062 }
1063
1064
1065 func TestManyCalls(t *testing.T) {
1066 t.Parallel()
1067
1068 if !testWork {
1069 defer func() {
1070 os.Remove("testp7" + exeSuffix)
1071 os.Remove("libgo7.a")
1072 os.Remove("libgo7.h")
1073 }()
1074 }
1075
1076 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
1077 out, err := cmd.CombinedOutput()
1078 t.Logf("%v\n%s", cmd.Args, out)
1079 if err != nil {
1080 t.Fatal(err)
1081 }
1082 checkLineComments(t, "libgo7.h")
1083 checkArchive(t, "libgo7.a")
1084
1085 ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
1086 if runtime.Compiler == "gccgo" {
1087 ccArgs = append(ccArgs, "-lgo")
1088 }
1089 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1090 t.Logf("%v\n%s", ccArgs, out)
1091 if err != nil {
1092 t.Fatal(err)
1093 }
1094
1095 argv := cmdToRun("./testp7")
1096 cmd = exec.Command(argv[0], argv[1:]...)
1097 sb := new(strings.Builder)
1098 cmd.Stdout = sb
1099 cmd.Stderr = sb
1100 if err := cmd.Start(); err != nil {
1101 t.Fatal(err)
1102 }
1103
1104 timer := time.AfterFunc(time.Minute,
1105 func() {
1106 t.Error("test program timed out")
1107 cmd.Process.Kill()
1108 },
1109 )
1110 defer timer.Stop()
1111
1112 err = cmd.Wait()
1113 t.Logf("%v\n%s", cmd.Args, sb)
1114 if err != nil {
1115 t.Error(err)
1116 }
1117 }
1118
1119
1120 func TestPreemption(t *testing.T) {
1121 if runtime.Compiler == "gccgo" {
1122 t.Skip("skipping asynchronous preemption test with gccgo")
1123 }
1124
1125 t.Parallel()
1126
1127 if !testWork {
1128 defer func() {
1129 os.Remove("testp8" + exeSuffix)
1130 os.Remove("libgo8.a")
1131 os.Remove("libgo8.h")
1132 }()
1133 }
1134
1135 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
1136 out, err := cmd.CombinedOutput()
1137 t.Logf("%v\n%s", cmd.Args, out)
1138 if err != nil {
1139 t.Fatal(err)
1140 }
1141 checkLineComments(t, "libgo8.h")
1142 checkArchive(t, "libgo8.a")
1143
1144 ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
1145 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
1146 t.Logf("%v\n%s", ccArgs, out)
1147 if err != nil {
1148 t.Fatal(err)
1149 }
1150
1151 argv := cmdToRun("./testp8")
1152 cmd = exec.Command(argv[0], argv[1:]...)
1153 sb := new(strings.Builder)
1154 cmd.Stdout = sb
1155 cmd.Stderr = sb
1156 if err := cmd.Start(); err != nil {
1157 t.Fatal(err)
1158 }
1159
1160 timer := time.AfterFunc(time.Minute,
1161 func() {
1162 t.Error("test program timed out")
1163 cmd.Process.Kill()
1164 },
1165 )
1166 defer timer.Stop()
1167
1168 err = cmd.Wait()
1169 t.Logf("%v\n%s", cmd.Args, sb)
1170 if err != nil {
1171 t.Error(err)
1172 }
1173 }
1174
View as plain text