1// Copyright 2018 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
5//go:build darwin && go1.12 && amd64
6// +build darwin,go1.12,amd64
7
8package unix
9
10import (
11	"os"
12	"os/exec"
13	"strings"
14	"testing"
15)
16
17type darwinTest struct {
18	name string
19	f    uintptr
20}
21
22// TODO(khr): decide whether to keep this test enabled permanently or
23// only temporarily.
24func TestDarwinLoader(t *testing.T) {
25	// Make sure the Darwin dynamic loader can actually resolve
26	// all the system calls into libSystem.dylib. Unfortunately
27	// there is no easy way to test this at compile time. So we
28	// implement a crazy hack here, calling into the syscall
29	// function with all its arguments set to junk, and see what
30	// error we get. We are happy with any error (or none) except
31	// an error from the dynamic loader.
32	//
33	// We have to run each test in a separate subprocess for fault isolation.
34	//
35	// Hopefully the junk args won't accidentally ask the system to do "rm -fr /".
36	//
37	// In an ideal world each syscall would have its own test, so this test
38	// would be unnecessary. Unfortunately, we do not live in that world.
39	for _, test := range darwinTests {
40		// Call the test binary recursively, giving it a magic argument
41		// (see init below) and the name of the test to run.
42		cmd := exec.Command(os.Args[0], "testDarwinLoader", test.name)
43
44		// Run subprocess, collect results. Note that we expect the subprocess
45		// to fail somehow, so the error is irrelevant.
46		out, _ := cmd.CombinedOutput()
47
48		if strings.Contains(string(out), "dyld: Symbol not found:") {
49			t.Errorf("can't resolve %s in libSystem.dylib", test.name)
50		}
51		if !strings.Contains(string(out), "success") {
52			// Not really an error. Might be a syscall that never returns,
53			// like exit, or one that segfaults, like gettimeofday.
54			t.Logf("test never finished: %s: %s", test.name, string(out))
55		}
56	}
57}
58
59func init() {
60	// The test binary execs itself with the "testDarwinLoader" argument.
61	// Run the test specified by os.Args[2], then panic.
62	if len(os.Args) >= 3 && os.Args[1] == "testDarwinLoader" {
63		for _, test := range darwinTests {
64			if test.name == os.Args[2] {
65				syscall_syscall(test.f, ^uintptr(0), ^uintptr(0), ^uintptr(0))
66			}
67		}
68		// Panic with a "success" label, so the parent process can check it.
69		panic("success")
70	}
71}
72
73// All the _trampoline functions in zsyscall_darwin_$ARCH.s
74var darwinTests = [...]darwinTest{
75	{"getgroups", libc_getgroups_trampoline_addr},
76	{"setgroups", libc_setgroups_trampoline_addr},
77	{"wait4", libc_wait4_trampoline_addr},
78	{"accept", libc_accept_trampoline_addr},
79	{"bind", libc_bind_trampoline_addr},
80	{"connect", libc_connect_trampoline_addr},
81	{"socket", libc_socket_trampoline_addr},
82	{"getsockopt", libc_getsockopt_trampoline_addr},
83	{"setsockopt", libc_setsockopt_trampoline_addr},
84	{"getpeername", libc_getpeername_trampoline_addr},
85	{"getsockname", libc_getsockname_trampoline_addr},
86	{"shutdown", libc_shutdown_trampoline_addr},
87	{"socketpair", libc_socketpair_trampoline_addr},
88	{"recvfrom", libc_recvfrom_trampoline_addr},
89	{"sendto", libc_sendto_trampoline_addr},
90	{"recvmsg", libc_recvmsg_trampoline_addr},
91	{"sendmsg", libc_sendmsg_trampoline_addr},
92	{"kevent", libc_kevent_trampoline_addr},
93	{"sysctl", libc_sysctl_trampoline_addr},
94	{"utimes", libc_utimes_trampoline_addr},
95	{"futimes", libc_futimes_trampoline_addr},
96	{"fcntl", libc_fcntl_trampoline_addr},
97	{"poll", libc_poll_trampoline_addr},
98	{"madvise", libc_madvise_trampoline_addr},
99	{"mlock", libc_mlock_trampoline_addr},
100	{"mlockall", libc_mlockall_trampoline_addr},
101	{"mprotect", libc_mprotect_trampoline_addr},
102	{"msync", libc_msync_trampoline_addr},
103	{"munlock", libc_munlock_trampoline_addr},
104	{"munlockall", libc_munlockall_trampoline_addr},
105	{"ptrace", libc_ptrace_trampoline_addr},
106	{"pipe", libc_pipe_trampoline_addr},
107	{"getxattr", libc_getxattr_trampoline_addr},
108	{"fgetxattr", libc_fgetxattr_trampoline_addr},
109	{"setxattr", libc_setxattr_trampoline_addr},
110	{"fsetxattr", libc_fsetxattr_trampoline_addr},
111	{"removexattr", libc_removexattr_trampoline_addr},
112	{"fremovexattr", libc_fremovexattr_trampoline_addr},
113	{"listxattr", libc_listxattr_trampoline_addr},
114	{"flistxattr", libc_flistxattr_trampoline_addr},
115	{"kill", libc_kill_trampoline_addr},
116	{"ioctl", libc_ioctl_trampoline_addr},
117	{"access", libc_access_trampoline_addr},
118	{"adjtime", libc_adjtime_trampoline_addr},
119	{"chdir", libc_chdir_trampoline_addr},
120	{"chflags", libc_chflags_trampoline_addr},
121	{"chmod", libc_chmod_trampoline_addr},
122	{"chown", libc_chown_trampoline_addr},
123	{"chroot", libc_chroot_trampoline_addr},
124	{"close", libc_close_trampoline_addr},
125	{"dup", libc_dup_trampoline_addr},
126	{"dup2", libc_dup2_trampoline_addr},
127	{"exchangedata", libc_exchangedata_trampoline_addr},
128	{"exit", libc_exit_trampoline_addr},
129	{"faccessat", libc_faccessat_trampoline_addr},
130	{"fchdir", libc_fchdir_trampoline_addr},
131	{"fchflags", libc_fchflags_trampoline_addr},
132	{"fchmod", libc_fchmod_trampoline_addr},
133	{"fchmodat", libc_fchmodat_trampoline_addr},
134	{"fchown", libc_fchown_trampoline_addr},
135	{"fchownat", libc_fchownat_trampoline_addr},
136	{"flock", libc_flock_trampoline_addr},
137	{"fpathconf", libc_fpathconf_trampoline_addr},
138	{"fstat64", libc_fstat64_trampoline_addr},
139	{"fstatat64", libc_fstatat64_trampoline_addr},
140	{"fstatfs64", libc_fstatfs64_trampoline_addr},
141	{"fsync", libc_fsync_trampoline_addr},
142	{"ftruncate", libc_ftruncate_trampoline_addr},
143	{"getdtablesize", libc_getdtablesize_trampoline_addr},
144	{"getegid", libc_getegid_trampoline_addr},
145	{"geteuid", libc_geteuid_trampoline_addr},
146	{"getgid", libc_getgid_trampoline_addr},
147	{"getpgid", libc_getpgid_trampoline_addr},
148	{"getpgrp", libc_getpgrp_trampoline_addr},
149	{"getpid", libc_getpid_trampoline_addr},
150	{"getppid", libc_getppid_trampoline_addr},
151	{"getpriority", libc_getpriority_trampoline_addr},
152	{"getrlimit", libc_getrlimit_trampoline_addr},
153	{"getrusage", libc_getrusage_trampoline_addr},
154	{"getsid", libc_getsid_trampoline_addr},
155	{"getuid", libc_getuid_trampoline_addr},
156	{"issetugid", libc_issetugid_trampoline_addr},
157	{"kqueue", libc_kqueue_trampoline_addr},
158	{"lchown", libc_lchown_trampoline_addr},
159	{"link", libc_link_trampoline_addr},
160	{"linkat", libc_linkat_trampoline_addr},
161	{"listen", libc_listen_trampoline_addr},
162	{"lstat64", libc_lstat64_trampoline_addr},
163	{"mkdir", libc_mkdir_trampoline_addr},
164	{"mkdirat", libc_mkdirat_trampoline_addr},
165	{"mkfifo", libc_mkfifo_trampoline_addr},
166	{"mknod", libc_mknod_trampoline_addr},
167	{"open", libc_open_trampoline_addr},
168	{"openat", libc_openat_trampoline_addr},
169	{"pathconf", libc_pathconf_trampoline_addr},
170	{"pread", libc_pread_trampoline_addr},
171	{"pwrite", libc_pwrite_trampoline_addr},
172	{"read", libc_read_trampoline_addr},
173	{"readlink", libc_readlink_trampoline_addr},
174	{"readlinkat", libc_readlinkat_trampoline_addr},
175	{"rename", libc_rename_trampoline_addr},
176	{"renameat", libc_renameat_trampoline_addr},
177	{"revoke", libc_revoke_trampoline_addr},
178	{"rmdir", libc_rmdir_trampoline_addr},
179	{"lseek", libc_lseek_trampoline_addr},
180	{"select", libc_select_trampoline_addr},
181	{"setegid", libc_setegid_trampoline_addr},
182	{"seteuid", libc_seteuid_trampoline_addr},
183	{"setgid", libc_setgid_trampoline_addr},
184	{"setlogin", libc_setlogin_trampoline_addr},
185	{"setpgid", libc_setpgid_trampoline_addr},
186	{"setpriority", libc_setpriority_trampoline_addr},
187	{"setprivexec", libc_setprivexec_trampoline_addr},
188	{"setregid", libc_setregid_trampoline_addr},
189	{"setreuid", libc_setreuid_trampoline_addr},
190	{"setrlimit", libc_setrlimit_trampoline_addr},
191	{"setsid", libc_setsid_trampoline_addr},
192	{"settimeofday", libc_settimeofday_trampoline_addr},
193	{"setuid", libc_setuid_trampoline_addr},
194	{"stat64", libc_stat64_trampoline_addr},
195	{"statfs64", libc_statfs64_trampoline_addr},
196	{"symlink", libc_symlink_trampoline_addr},
197	{"symlinkat", libc_symlinkat_trampoline_addr},
198	{"sync", libc_sync_trampoline_addr},
199	{"truncate", libc_truncate_trampoline_addr},
200	{"umask", libc_umask_trampoline_addr},
201	{"undelete", libc_undelete_trampoline_addr},
202	{"unlink", libc_unlink_trampoline_addr},
203	{"unlinkat", libc_unlinkat_trampoline_addr},
204	{"unmount", libc_unmount_trampoline_addr},
205	{"write", libc_write_trampoline_addr},
206	{"mmap", libc_mmap_trampoline_addr},
207	{"munmap", libc_munmap_trampoline_addr},
208	{"gettimeofday", libc_gettimeofday_trampoline_addr},
209	{"getfsstat64", libc_getfsstat64_trampoline_addr},
210}
211