"debug/elf"
"flag"
"fmt"
+ "io/fs"
"log"
"os"
"os/exec"
var badLineRegexp = regexp.MustCompile(`(?m)^#line [0-9]+ "/.*$`)
+// checkIsExecutable verifies that exe exists and has execute permission.
+//
+// (https://golang.org/issue/49693 notes failures with "no such file or
+// directory", so we want to double-check that the executable actually exists
+// immediately after we build it in order to better understand that failure
+// mode.)
+func checkIsExecutable(t *testing.T, exe string) {
+ t.Helper()
+ fi, err := os.Stat(exe)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if runtime.GOOS == "windows" {
+ // os.File doesn't check the "execute" permission on Windows files
+ // and as a result doesn't set that bit in a file's permissions.
+ // Assume that if the file exists it is “executable enough”.
+ return
+ }
+ if fi.Mode()&0111 == 0 {
+ t.Fatalf("%s is not executable: %0o", exe, fi.Mode()&fs.ModePerm)
+ }
+}
+
// checkLineComments checks that the export header generated by
// -buildmode=c-archive doesn't have any absolute paths in the #line
// comments. We don't want those paths because they are unhelpful for
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd = exec.Command(bin[0], append(bin[1:], "1")...)
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", cmd.Args, out)
expectSignal(t, err, syscall.SIGSEGV)
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
cmd = exec.Command(bin[0], append(bin[1:], "3")...)
out, err = cmd.CombinedOutput()
- t.Logf("%s", out)
+ if len(out) > 0 {
+ t.Logf("%s", out)
+ }
expectSignal(t, err, syscall.SIGPIPE)
}
}
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
defer func() {
os.Remove("libgo3.a")
os.Remove("libgo3.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
- os.Remove("testp")
+ os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo6.h")
if runtime.Compiler == "gccgo" {
ccArgs = append(ccArgs, "-lgo")
}
- if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
t.Fatal(err)
}
+ checkIsExecutable(t, "./testp6"+exeSuffix)
argv := cmdToRun("./testp6")
cmd = exec.Command(argv[0], argv[1:]...)
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err = cmd.CombinedOutput()
+ t.Logf("%v\n%s", argv, out)
+ if err != nil {
t.Fatal(err)
}
}
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
- t.Log(cmd.Args)
out, err := cmd.CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", cmd.Args, out)
if err != nil {
t.Fatal(err)
}
if runtime.Compiler == "gccgo" {
ccArgs = append(ccArgs, "-lgo")
}
- t.Log(ccArgs)
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
// If -no-pie unrecognized, try -nopie if this is possibly clang
if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") {
ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a")
- t.Log(ccArgs)
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
}
// Don't use either -no-pie or -nopie
if err != nil && bytes.Contains(out, []byte("unrecognized")) {
- ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
- t.Log(ccArgs)
+ ccArgs = append(cc, "-o", exe, "main5.c", "libgo2.a")
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
}
- t.Logf("%s", out)
if err != nil {
t.Fatal(err)
}
}
binArgs := append(cmdToRun(exe), "1")
- t.Log(binArgs)
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", binArgs, out)
expectSignal(t, err, syscall.SIGSEGV)
// SIGPIPE is never forwarded on darwin. See golang.org/issue/33384.
if runtime.GOOS != "darwin" && runtime.GOOS != "ios" {
binArgs := append(cmdToRun(exe), "3")
- t.Log(binArgs)
out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
- t.Logf("%s", out)
+ t.Logf("%v\n%s", binArgs, out)
expectSignal(t, err, syscall.SIGPIPE)
}
}
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo7.h")
if runtime.Compiler == "gccgo" {
ccArgs = append(ccArgs, "-lgo")
}
- if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
t.Fatal(err)
}
+ checkIsExecutable(t, "./testp7"+exeSuffix)
argv := cmdToRun("./testp7")
cmd = exec.Command(argv[0], argv[1:]...)
- var sb strings.Builder
- cmd.Stdout = &sb
- cmd.Stderr = &sb
+ sb := new(strings.Builder)
+ cmd.Stdout = sb
+ cmd.Stderr = sb
if err := cmd.Start(); err != nil {
t.Fatal(err)
}
)
defer timer.Stop()
- if err := cmd.Wait(); err != nil {
- t.Log(sb.String())
+ err = cmd.Wait()
+ t.Logf("%v\n%s", cmd.Args, sb)
+ if err != nil {
t.Error(err)
}
}
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
t.Fatal(err)
}
checkLineComments(t, "libgo8.h")
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
- if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
t.Fatal(err)
}
+ checkIsExecutable(t, "./testp8"+exeSuffix)
argv := cmdToRun("./testp8")
cmd = exec.Command(argv[0], argv[1:]...)
- var sb strings.Builder
- cmd.Stdout = &sb
- cmd.Stderr = &sb
+ sb := new(strings.Builder)
+ cmd.Stdout = sb
+ cmd.Stderr = sb
if err := cmd.Start(); err != nil {
t.Fatal(err)
}
)
defer timer.Stop()
- if err := cmd.Wait(); err != nil {
- t.Log(sb.String())
+ err = cmd.Wait()
+ t.Logf("%v\n%s", cmd.Args, sb)
+ if err != nil {
t.Error(err)
}
}