Deleted Added
full compact
accept_fd_leak.c (256281) accept_fd_leak.c (281974)
1/*-
2 * Copyright (c) 2004 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2004 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c 168273 2007-04-02 16:02:50Z jhb $
26 * $FreeBSD: stable/10/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c 281974 2015-04-25 05:31:52Z ngie $
27 */
28
27 */
28
29#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <sys/wait.h>
32
33#include <netinet/in.h>
34
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <signal.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
30#include <sys/socket.h>
31#include <sys/wait.h>
32
33#include <netinet/in.h>
34
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <signal.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#define BIND_ATTEMPTS 10
44#define LOOPS 500
45#define LOOPS 500
46#define NUM_ATTEMPTS 1000
45
47
46volatile int quit;
48static volatile int quit;
47
48static void
49
50static void
49child_died(int sig)
51child_died(int sig __unused)
50{
52{
53
51 quit = 1;
52}
53
54/*
55 * This test is intended to detect a leak of a file descriptor in the process
56 * following a failed non-blocking accept. It measures an available fd
57 * baseline, then performs 1000 failing accepts, then checks to see what the
58 * next fd is. It relies on sequential fd allocation, and will test for it
59 * briefly before beginning (not 100% reliable, but a good start).
60 */
61int
54 quit = 1;
55}
56
57/*
58 * This test is intended to detect a leak of a file descriptor in the process
59 * following a failed non-blocking accept. It measures an available fd
60 * baseline, then performs 1000 failing accepts, then checks to see what the
61 * next fd is. It relies on sequential fd allocation, and will test for it
62 * briefly before beginning (not 100% reliable, but a good start).
63 */
64int
62main(int argc, char *argv[])
65main(void)
63{
64 struct sockaddr_in sin;
65 socklen_t size;
66 pid_t child;
66{
67 struct sockaddr_in sin;
68 socklen_t size;
69 pid_t child;
67 int fd1, fd2, fd3, i, s;
68 int status;
70 int fd1, fd2, fd3, i, listen_port, s, status;
69
70 printf("1..2\n");
71
72 /*
73 * Check for sequential fd allocation, and give up early if not.
74 */
75 fd1 = dup(STDIN_FILENO);
76 fd2 = dup(STDIN_FILENO);
77 if (fd2 != fd1 + 1)
78 errx(-1, "Non-sequential fd allocation\n");
79
80 s = socket(PF_INET, SOCK_STREAM, 0);
81 if (s == -1)
82 errx(-1, "socket: %s", strerror(errno));
83
84 bzero(&sin, sizeof(sin));
85 sin.sin_len = sizeof(sin);
86 sin.sin_family = AF_INET;
87 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
71
72 printf("1..2\n");
73
74 /*
75 * Check for sequential fd allocation, and give up early if not.
76 */
77 fd1 = dup(STDIN_FILENO);
78 fd2 = dup(STDIN_FILENO);
79 if (fd2 != fd1 + 1)
80 errx(-1, "Non-sequential fd allocation\n");
81
82 s = socket(PF_INET, SOCK_STREAM, 0);
83 if (s == -1)
84 errx(-1, "socket: %s", strerror(errno));
85
86 bzero(&sin, sizeof(sin));
87 sin.sin_len = sizeof(sin);
88 sin.sin_family = AF_INET;
89 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
88 sin.sin_port = htons(8080);
89
90
90 if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) != 0)
91 errx(-1, "bind: %s", strerror(errno));
91 srandomdev();
92
92
93 for (i = 0; i < BIND_ATTEMPTS; i++) {
94 /* Pick a random unprivileged port 1025-65535 */
95 listen_port = MAX((int)random() % 65535, 1025);
96 sin.sin_port = htons(listen_port);
97 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0)
98 break;
99 warn("bind with %d failed", listen_port);
100 usleep(1000);
101 }
102 if (i >= BIND_ATTEMPTS) {
103 printf("Bail out!\n");
104 exit(1);
105 }
106
93 if (listen(s, -1) != 0)
94 errx(-1, "listen: %s", strerror(errno));
95
96 i = fcntl(s, F_GETFL);
97 if (i == -1)
98 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
99 i |= O_NONBLOCK;
100 if (fcntl(s, F_SETFL, i) != 0)

--- 28 unchanged lines hidden (view full) ---

129 */
130 close(fd3);
131 signal(SIGCHLD, child_died);
132 child = fork();
133 if (child < 0)
134 errx(-1, "fork: %s", strerror(errno));
135
136 /*
107 if (listen(s, -1) != 0)
108 errx(-1, "listen: %s", strerror(errno));
109
110 i = fcntl(s, F_GETFL);
111 if (i == -1)
112 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
113 i |= O_NONBLOCK;
114 if (fcntl(s, F_SETFL, i) != 0)

--- 28 unchanged lines hidden (view full) ---

143 */
144 close(fd3);
145 signal(SIGCHLD, child_died);
146 child = fork();
147 if (child < 0)
148 errx(-1, "fork: %s", strerror(errno));
149
150 /*
137 * Child process does 1000 connect's.
151 * Child process does `NUM_ATTEMPTS` connects.
138 */
139 if (child == 0) {
152 */
153 if (child == 0) {
154 close(fd1);
155 close(fd2);
156 close(s);
157
140 bzero(&sin, sizeof(sin));
141 sin.sin_len = sizeof(sin);
142 sin.sin_family = AF_INET;
143 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
158 bzero(&sin, sizeof(sin));
159 sin.sin_len = sizeof(sin);
160 sin.sin_family = AF_INET;
161 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
144 sin.sin_port = htons(8080);
162 sin.sin_port = htons(listen_port);
145
163
146 for (i = 0; i < 1000; i++) {
164 for (i = 0; i < NUM_ATTEMPTS; i++) {
147 s = socket(PF_INET, SOCK_STREAM, 0);
148 if (s == -1)
149 errx(-1, "socket: %s", strerror(errno));
150 if (connect(s, (struct sockaddr *)&sin,
151 sizeof(sin)) < 0)
152 errx(-1, "connect: %s", strerror(errno));
153 close(s);
154 }
165 s = socket(PF_INET, SOCK_STREAM, 0);
166 if (s == -1)
167 errx(-1, "socket: %s", strerror(errno));
168 if (connect(s, (struct sockaddr *)&sin,
169 sizeof(sin)) < 0)
170 errx(-1, "connect: %s", strerror(errno));
171 close(s);
172 }
155 exit(0);
173 _exit(0);
156 }
157
158 /* Reset back to a blocking socket. */
159 i = fcntl(s, F_GETFL);
160 if (i == -1)
161 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
162 i &= ~O_NONBLOCK;
163 if (fcntl(s, F_SETFL, i) != 0)
164 errx(-1, "ioctl(F_SETFL): %s", strerror(errno));
165 i = fcntl(s, F_GETFL);
166 if (i == -1)
167 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
168 if (i & O_NONBLOCK)
169 errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i);
174 }
175
176 /* Reset back to a blocking socket. */
177 i = fcntl(s, F_GETFL);
178 if (i == -1)
179 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
180 i &= ~O_NONBLOCK;
181 if (fcntl(s, F_SETFL, i) != 0)
182 errx(-1, "ioctl(F_SETFL): %s", strerror(errno));
183 i = fcntl(s, F_GETFL);
184 if (i == -1)
185 errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
186 if (i & O_NONBLOCK)
187 errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i);
170
171 /* Do 1000 accept's with an invalid pointer. */
172 for (i = 0; !quit && i < 1000; i++) {
188
189 /* Do `NUM_ATTEMPTS` accepts with an invalid pointer. */
190 for (i = 0; !quit && i < NUM_ATTEMPTS; i++) {
173 size = sizeof(sin);
174 if (accept(s, (struct sockaddr *)(uintptr_t)(0x100),
175 &size) != -1)
176 errx(-1, "accept succeeded\n");
177 if (errno != EFAULT)
178 errx(-1, "accept: %s", strerror(errno));
179 }
180
181 if (waitpid(child, &status, 0) < 0)
182 errx(-1, "waitpid: %s", strerror(errno));
183 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
184 warnx("child process died");
191 size = sizeof(sin);
192 if (accept(s, (struct sockaddr *)(uintptr_t)(0x100),
193 &size) != -1)
194 errx(-1, "accept succeeded\n");
195 if (errno != EFAULT)
196 errx(-1, "accept: %s", strerror(errno));
197 }
198
199 if (waitpid(child, &status, 0) < 0)
200 errx(-1, "waitpid: %s", strerror(errno));
201 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
202 warnx("child process died");
185
203
186 /*
187 * Allocate a file descriptor and make sure it's fd2+2. 2 because
188 * we allocate an fd for the socket.
189 */
190 fd3 = dup(STDIN_FILENO);
191 if (fd3 != fd2 + 2)
192 printf("not ok 2 - (%d, %d, %d)\n", fd1, fd2, fd3);
193 else
194 printf("ok 2\n");
195
196 return (0);
197}
204 /*
205 * Allocate a file descriptor and make sure it's fd2+2. 2 because
206 * we allocate an fd for the socket.
207 */
208 fd3 = dup(STDIN_FILENO);
209 if (fd3 != fd2 + 2)
210 printf("not ok 2 - (%d, %d, %d)\n", fd1, fd2, fd3);
211 else
212 printf("ok 2\n");
213
214 return (0);
215}