summaryrefslogtreecommitdiffstats
path: root/tools/regression/sockets
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-04-02 16:02:50 +0000
committerjhb <jhb@FreeBSD.org>2007-04-02 16:02:50 +0000
commit6880657bf36962cd0261eda663616720df634bf2 (patch)
tree7583cc1c0df42ddb6b86e3c49801a7059fef9e10 /tools/regression/sockets
parentc8bd325d08025c25cacb77438cae0cff65aa5e8c (diff)
downloadFreeBSD-src-6880657bf36962cd0261eda663616720df634bf2.zip
FreeBSD-src-6880657bf36962cd0261eda663616720df634bf2.tar.gz
Add another fd leak test for accept() I used to test the fix in 1.234 of
sys/kern/uipc_syscall.c.
Diffstat (limited to 'tools/regression/sockets')
-rw-r--r--tools/regression/sockets/accept_fd_leak/accept_fd_leak.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c b/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
index 9bf946d..32d4edf 100644
--- a/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
+++ b/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c
@@ -28,12 +28,14 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <netinet/in.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,6 +43,14 @@
#define LOOPS 500
+volatile int quit;
+
+static void
+child_died(int sig)
+{
+ quit = 1;
+}
+
/*
* This test is intended to detect a leak of a file descriptor in the process
* following a failed non-blocking accept. It measures an available fd
@@ -53,9 +63,11 @@ main(int argc, char *argv[])
{
struct sockaddr_in sin;
socklen_t size;
+ pid_t child;
int fd1, fd2, fd3, i, s;
+ int status;
- printf("1..1\n");
+ printf("1..2\n");
/*
* Check for sequential fd allocation, and give up early if not.
@@ -111,5 +123,75 @@ main(int argc, char *argv[])
else
printf("ok 1\n");
+ /*
+ * Try failing accept's w/o non-blocking where the destination
+ * address pointer is invalid.
+ */
+ close(fd3);
+ signal(SIGCHLD, child_died);
+ child = fork();
+ if (child < 0)
+ errx(-1, "fork: %s", strerror(errno));
+
+ /*
+ * Child process does 1000 connect's.
+ */
+ if (child == 0) {
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sin.sin_port = htons(8080);
+
+ for (i = 0; i < 1000; i++) {
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s == -1)
+ errx(-1, "socket: %s", strerror(errno));
+ if (connect(s, (struct sockaddr *)&sin,
+ sizeof(sin)) < 0)
+ errx(-1, "connect: %s", strerror(errno));
+ close(s);
+ }
+ exit(0);
+ }
+
+ /* Reset back to a blocking socket. */
+ i = fcntl(s, F_GETFL);
+ if (i == -1)
+ errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
+ i &= ~O_NONBLOCK;
+ if (fcntl(s, F_SETFL, i) != 0)
+ errx(-1, "ioctl(F_SETFL): %s", strerror(errno));
+ i = fcntl(s, F_GETFL);
+ if (i == -1)
+ errx(-1, "ioctl(F_GETFL): %s", strerror(errno));
+ if (i & O_NONBLOCK)
+ errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i);
+
+ /* Do 1000 accept's with an invalid pointer. */
+ for (i = 0; !quit && i < 1000; i++) {
+ size = sizeof(sin);
+ if (accept(s, (struct sockaddr *)(uintptr_t)(0x100),
+ &size) != -1)
+ errx(-1, "accept succeeded\n");
+ if (errno != EFAULT)
+ errx(-1, "accept: %s", strerror(errno));
+ }
+
+ if (waitpid(child, &status, 0) < 0)
+ errx(-1, "waitpid: %s", strerror(errno));
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ warnx("child process died");
+
+ /*
+ * Allocate a file descriptor and make sure it's fd2+2. 2 because
+ * we allocate an fd for the socket.
+ */
+ fd3 = dup(STDIN_FILENO);
+ if (fd3 != fd2 + 2)
+ printf("not ok 2 - (%d, %d, %d)\n", fd1, fd2, fd3);
+ else
+ printf("ok 2\n");
+
return (0);
}
OpenPOWER on IntegriCloud