mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
Add another fd leak test for accept() I used to test the fix in 1.234 of
sys/kern/uipc_syscall.c.
This commit is contained in:
parent
1b0a8a3e52
commit
c16551befc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=168273
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user