]> git.saurik.com Git - apple/xnu.git/blob - tests/fd.c
xnu-7195.60.75.tar.gz
[apple/xnu.git] / tests / fd.c
1 #include <darwintest.h>
2 #include <darwintest_utils.h>
3 #include <pthread.h>
4 #include <sys/select.h>
5 #include <sys/fileport.h>
6 #include <sys/fcntl.h>
7 #include <mach/mach.h>
8
9 T_GLOBAL_META(
10 T_META_RUN_CONCURRENTLY(true),
11 T_META_LTEPHASE(LTE_POSTINIT)
12 );
13
14 static void *
15 fd_select_close_helper(void *ctx)
16 {
17 int fd = *(int *)ctx;
18
19 // wait for the thread to enter select
20 usleep(500000);
21 close(fd);
22
23 return NULL;
24 }
25
26 T_DECL(fd_select_close, "Test for 54795873: make sure close breaks out of select")
27 {
28 fd_set read_fd;
29 int pair[2], rc;
30 pthread_t th;
31
32 rc = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
33 T_ASSERT_POSIX_SUCCESS(rc, "socketpair");
34
35 pthread_create(&th, NULL, fd_select_close_helper, pair);
36
37 FD_ZERO(&read_fd);
38 FD_SET(pair[0], &read_fd);
39
40 rc = select(pair[0] + 1, &read_fd, NULL, NULL, NULL);
41 T_EXPECT_POSIX_FAILURE(rc, EBADF, "select broke out with EBADF");
42 }
43
44 static void *
45 fd_stress_dup2_close_fun(void *ctx)
46 {
47 int thno = (int)(long)ctx;
48 int count = 10000, rc;
49
50 for (int i = 1; i <= count; i++) {
51 rc = dup2(STDIN_FILENO, 42);
52 T_QUIET; T_EXPECT_POSIX_SUCCESS(rc, "dup2(%d, 42)", STDIN_FILENO);
53 if (thno == 3) {
54 rc = close(42);
55 if (rc == -1) {
56 T_QUIET; T_EXPECT_POSIX_FAILURE(rc, EBADF, "close(42)");
57 }
58 }
59 if (i % 1000 == 0) {
60 T_LOG("thread %d: %d/%d dups\n", thno, i, count);
61 }
62 }
63
64 return NULL;
65 }
66
67 T_DECL(fd_stress_dup2_close, "Stress test races between dup2 and close")
68 {
69 pthread_t th[4];
70 int rc;
71
72 for (int i = 0; i < 4; i++) {
73 rc = pthread_create(&th[i], NULL,
74 fd_stress_dup2_close_fun, (void *)(long)i);
75 T_ASSERT_POSIX_ZERO(rc, "pthread_create");
76 }
77
78 for (int i = 0; i < 4; i++) {
79 pthread_join(th[i], NULL);
80 }
81 }
82
83 T_DECL(fd_dup2_erase_clofork_58446996,
84 "Make sure dup2() doesn't inherit flags from an old fd")
85 {
86 int fd1, fd2;
87
88 fd1 = open("/dev/null", O_RDONLY | O_CLOEXEC);
89 T_ASSERT_POSIX_SUCCESS(fd1, "open(/dev/null)");
90
91 fd2 = open("/dev/null", O_RDONLY | O_CLOEXEC);
92 T_ASSERT_POSIX_SUCCESS(fd2, "open(/dev/null)");
93
94 T_ASSERT_POSIX_SUCCESS(dup2(fd1, fd2), "dup2(fd1, fd2)");
95 T_EXPECT_EQ(fcntl(fd2, F_GETFD, 0), 0,
96 "neither FD_CLOEXEC nor FD_CLOFORK should be set");
97 }
98
99 struct confined_race_state {
100 int fd;
101 bool made;
102 };
103
104 static void *
105 confine_thread(void *data)
106 {
107 volatile int *fdp = data;
108
109 for (;;) {
110 fcntl(*fdp, F_SETCONFINED, 1);
111 }
112
113 return NULL;
114 }
115
116 T_DECL(confined_fileport_race, "test for rdar://69922255")
117 {
118 int fd = -1;
119 pthread_t t;
120 mach_port_t p = MACH_PORT_NULL;
121
122 T_ASSERT_POSIX_SUCCESS(pthread_create(&t, NULL, confine_thread, &fd),
123 "pthread_create");
124
125 for (int i = 0; i < 100 * 1000; i++) {
126 fd = open("/dev/null", O_RDONLY | 0x08000000 /* O_CLOFORK */);
127 T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "open(/dev/null)");
128 if (fileport_makeport(fd, &p) == 0) {
129 T_QUIET; T_ASSERT_EQ(fcntl(fd, F_GETCONFINED), 0,
130 "should never get a confined fd: %d", fd);
131 mach_port_destroy(mach_task_self(), p);
132 }
133
134 close(fd);
135 }
136 }