carchive_test.go 30 KB

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