// 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}, }