--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin,go1.12,amd64 darwin,go1.12,386
+
+package unix
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+type darwinTest struct {
+ name string
+ f func()
+}
+
+// TODO(khr): decide whether to keep this test enabled permanently or
+// only temporarily.
+func TestDarwinLoader(t *testing.T) {
+ // Make sure the Darwin dynamic loader can actually resolve
+ // all the system calls into libSystem.dylib. Unfortunately
+ // there is no easy way to test this at compile time. So we
+ // implement a crazy hack here, calling into the syscall
+ // function with all its arguments set to junk, and see what
+ // error we get. We are happy with any error (or none) except
+ // an error from the dynamic loader.
+ //
+ // We have to run each test in a separate subprocess for fault isolation.
+ //
+ // Hopefully the junk args won't accidentally ask the system to do "rm -fr /".
+ //
+ // In an ideal world each syscall would have its own test, so this test
+ // would be unnecessary. Unfortunately, we do not live in that world.
+ for _, test := range darwinTests {
+ // Call the test binary recursively, giving it a magic argument
+ // (see init below) and the name of the test to run.
+ cmd := exec.Command(os.Args[0], "testDarwinLoader", test.name)
+
+ // Run subprocess, collect results. Note that we expect the subprocess
+ // to fail somehow, so the error is irrelevant.
+ out, _ := cmd.CombinedOutput()
+
+ if strings.Contains(string(out), "dyld: Symbol not found:") {
+ t.Errorf("can't resolve %s in libSystem.dylib", test.name)
+ }
+ if !strings.Contains(string(out), "success") {
+ // Not really an error. Might be a syscall that never returns,
+ // like exit, or one that segfaults, like gettimeofday.
+ t.Logf("test never finished: %s: %s", test.name, string(out))
+ }
+ }
+}
+
+func init() {
+ // The test binary execs itself with the "testDarwinLoader" argument.
+ // Run the test specified by os.Args[2], then panic.
+ if len(os.Args) >= 3 && os.Args[1] == "testDarwinLoader" {
+ for _, test := range darwinTests {
+ if test.name == os.Args[2] {
+ test.f()
+ }
+ }
+ // Panic with a "success" label, so the parent process can check it.
+ panic("success")
+ }
+}
+
+// All the _trampoline functions in zsyscall_darwin_$ARCH.s
+var darwinTests = [...]darwinTest{
+ {"getgroups", libc_getgroups_trampoline},
+ {"setgroups", libc_setgroups_trampoline},
+ {"wait4", libc_wait4_trampoline},
+ {"accept", libc_accept_trampoline},
+ {"bind", libc_bind_trampoline},
+ {"connect", libc_connect_trampoline},
+ {"socket", libc_socket_trampoline},
+ {"getsockopt", libc_getsockopt_trampoline},
+ {"setsockopt", libc_setsockopt_trampoline},
+ {"getpeername", libc_getpeername_trampoline},
+ {"getsockname", libc_getsockname_trampoline},
+ {"shutdown", libc_shutdown_trampoline},
+ {"socketpair", libc_socketpair_trampoline},
+ {"recvfrom", libc_recvfrom_trampoline},
+ {"sendto", libc_sendto_trampoline},
+ {"recvmsg", libc_recvmsg_trampoline},
+ {"sendmsg", libc_sendmsg_trampoline},
+ {"kevent", libc_kevent_trampoline},
+ {"sysctl", libc_sysctl_trampoline},
+ {"utimes", libc_utimes_trampoline},
+ {"futimes", libc_futimes_trampoline},
+ {"fcntl", libc_fcntl_trampoline},
+ {"poll", libc_poll_trampoline},
+ {"madvise", libc_madvise_trampoline},
+ {"mlock", libc_mlock_trampoline},
+ {"mlockall", libc_mlockall_trampoline},
+ {"mprotect", libc_mprotect_trampoline},
+ {"msync", libc_msync_trampoline},
+ {"munlock", libc_munlock_trampoline},
+ {"munlockall", libc_munlockall_trampoline},
+ {"ptrace", libc_ptrace_trampoline},
+ {"pipe", libc_pipe_trampoline},
+ {"getxattr", libc_getxattr_trampoline},
+ {"fgetxattr", libc_fgetxattr_trampoline},
+ {"setxattr", libc_setxattr_trampoline},
+ {"fsetxattr", libc_fsetxattr_trampoline},
+ {"removexattr", libc_removexattr_trampoline},
+ {"fremovexattr", libc_fremovexattr_trampoline},
+ {"listxattr", libc_listxattr_trampoline},
+ {"flistxattr", libc_flistxattr_trampoline},
+ {"kill", libc_kill_trampoline},
+ {"ioctl", libc_ioctl_trampoline},
+ {"access", libc_access_trampoline},
+ {"adjtime", libc_adjtime_trampoline},
+ {"chdir", libc_chdir_trampoline},
+ {"chflags", libc_chflags_trampoline},
+ {"chmod", libc_chmod_trampoline},
+ {"chown", libc_chown_trampoline},
+ {"chroot", libc_chroot_trampoline},
+ {"close", libc_close_trampoline},
+ {"dup", libc_dup_trampoline},
+ {"dup2", libc_dup2_trampoline},
+ {"exchangedata", libc_exchangedata_trampoline},
+ {"exit", libc_exit_trampoline},
+ {"faccessat", libc_faccessat_trampoline},
+ {"fchdir", libc_fchdir_trampoline},
+ {"fchflags", libc_fchflags_trampoline},
+ {"fchmod", libc_fchmod_trampoline},
+ {"fchmodat", libc_fchmodat_trampoline},
+ {"fchown", libc_fchown_trampoline},
+ {"fchownat", libc_fchownat_trampoline},
+ {"flock", libc_flock_trampoline},
+ {"fpathconf", libc_fpathconf_trampoline},
+ {"fstat64", libc_fstat64_trampoline},
+ {"fstatat64", libc_fstatat64_trampoline},
+ {"fstatfs64", libc_fstatfs64_trampoline},
+ {"fsync", libc_fsync_trampoline},
+ {"ftruncate", libc_ftruncate_trampoline},
+ {"getdtablesize", libc_getdtablesize_trampoline},
+ {"getegid", libc_getegid_trampoline},
+ {"geteuid", libc_geteuid_trampoline},
+ {"getgid", libc_getgid_trampoline},
+ {"getpgid", libc_getpgid_trampoline},
+ {"getpgrp", libc_getpgrp_trampoline},
+ {"getpid", libc_getpid_trampoline},
+ {"getppid", libc_getppid_trampoline},
+ {"getpriority", libc_getpriority_trampoline},
+ {"getrlimit", libc_getrlimit_trampoline},
+ {"getrusage", libc_getrusage_trampoline},
+ {"getsid", libc_getsid_trampoline},
+ {"getuid", libc_getuid_trampoline},
+ {"issetugid", libc_issetugid_trampoline},
+ {"kqueue", libc_kqueue_trampoline},
+ {"lchown", libc_lchown_trampoline},
+ {"link", libc_link_trampoline},
+ {"linkat", libc_linkat_trampoline},
+ {"listen", libc_listen_trampoline},
+ {"lstat64", libc_lstat64_trampoline},
+ {"mkdir", libc_mkdir_trampoline},
+ {"mkdirat", libc_mkdirat_trampoline},
+ {"mkfifo", libc_mkfifo_trampoline},
+ {"mknod", libc_mknod_trampoline},
+ {"open", libc_open_trampoline},
+ {"openat", libc_openat_trampoline},
+ {"pathconf", libc_pathconf_trampoline},
+ {"pread", libc_pread_trampoline},
+ {"pwrite", libc_pwrite_trampoline},
+ {"read", libc_read_trampoline},
+ {"readlink", libc_readlink_trampoline},
+ {"readlinkat", libc_readlinkat_trampoline},
+ {"rename", libc_rename_trampoline},
+ {"renameat", libc_renameat_trampoline},
+ {"revoke", libc_revoke_trampoline},
+ {"rmdir", libc_rmdir_trampoline},
+ {"lseek", libc_lseek_trampoline},
+ {"select", libc_select_trampoline},
+ {"setegid", libc_setegid_trampoline},
+ {"seteuid", libc_seteuid_trampoline},
+ {"setgid", libc_setgid_trampoline},
+ {"setlogin", libc_setlogin_trampoline},
+ {"setpgid", libc_setpgid_trampoline},
+ {"setpriority", libc_setpriority_trampoline},
+ {"setprivexec", libc_setprivexec_trampoline},
+ {"setregid", libc_setregid_trampoline},
+ {"setreuid", libc_setreuid_trampoline},
+ {"setrlimit", libc_setrlimit_trampoline},
+ {"setsid", libc_setsid_trampoline},
+ {"settimeofday", libc_settimeofday_trampoline},
+ {"setuid", libc_setuid_trampoline},
+ {"stat64", libc_stat64_trampoline},
+ {"statfs64", libc_statfs64_trampoline},
+ {"symlink", libc_symlink_trampoline},
+ {"symlinkat", libc_symlinkat_trampoline},
+ {"sync", libc_sync_trampoline},
+ {"truncate", libc_truncate_trampoline},
+ {"umask", libc_umask_trampoline},
+ {"undelete", libc_undelete_trampoline},
+ {"unlink", libc_unlink_trampoline},
+ {"unlinkat", libc_unlinkat_trampoline},
+ {"unmount", libc_unmount_trampoline},
+ {"write", libc_write_trampoline},
+ {"mmap", libc_mmap_trampoline},
+ {"munmap", libc_munmap_trampoline},
+ {"gettimeofday", libc_gettimeofday_trampoline},
+ {"getfsstat64", libc_getfsstat64_trampoline},
+}