diff options
author | jhb <jhb@FreeBSD.org> | 2007-04-02 16:02:50 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-04-02 16:02:50 +0000 |
commit | 6880657bf36962cd0261eda663616720df634bf2 (patch) | |
tree | 7583cc1c0df42ddb6b86e3c49801a7059fef9e10 /tools/regression/sockets | |
parent | c8bd325d08025c25cacb77438cae0cff65aa5e8c (diff) | |
download | FreeBSD-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.c | 84 |
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); } |