mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2026-02-16 22:05:55 -05:00
Merge remote-tracking branch 'pq/for-krh'
This commit is contained in:
commit
5be33520b3
8 changed files with 444 additions and 29 deletions
|
|
@ -39,6 +39,8 @@ if test "x$GCC" = "xyes"; then
|
|||
fi
|
||||
AC_SUBST(GCC_CFLAGS)
|
||||
|
||||
AC_CHECK_FUNCS([accept4])
|
||||
|
||||
AC_ARG_ENABLE([scanner],
|
||||
[AC_HELP_STRING([--disable-scanner],
|
||||
[Disable compilation of wayland-scannner])],
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "wayland-util.h"
|
||||
#include "wayland-private.h"
|
||||
#include "wayland-os.h"
|
||||
|
||||
#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
|
||||
|
||||
|
|
@ -306,7 +307,7 @@ wl_connection_data(struct wl_connection *connection, uint32_t mask)
|
|||
msg.msg_flags = 0;
|
||||
|
||||
do {
|
||||
len = recvmsg(connection->fd, &msg, MSG_CMSG_CLOEXEC);
|
||||
len = wl_os_recvmsg_cloexec(connection->fd, &msg, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
if (len < 0) {
|
||||
|
|
@ -518,7 +519,7 @@ wl_closure_vmarshal(struct wl_closure *closure,
|
|||
extra += sizeof *fd_ptr;
|
||||
|
||||
fd = va_arg(ap, int);
|
||||
dup_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
dup_fd = wl_os_dupfd_cloexec(fd, 0);
|
||||
if (dup_fd < 0) {
|
||||
fprintf(stderr, "dup failed: %m");
|
||||
abort();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include "wayland-server.h"
|
||||
#include "wayland-os.h"
|
||||
|
||||
struct wl_event_loop {
|
||||
int epoll_fd;
|
||||
|
|
@ -392,7 +393,7 @@ wl_event_loop_create(void)
|
|||
if (loop == NULL)
|
||||
return NULL;
|
||||
|
||||
loop->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
loop->epoll_fd = wl_os_epoll_create_cloexec();
|
||||
if (loop->epoll_fd < 0) {
|
||||
free(loop);
|
||||
return NULL;
|
||||
|
|
|
|||
101
src/wayland-os.c
101
src/wayland-os.c
|
|
@ -20,12 +20,16 @@
|
|||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "wayland-os.h"
|
||||
|
||||
static int
|
||||
|
|
@ -55,15 +59,106 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
|
|||
{
|
||||
int fd;
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
errno = 0;
|
||||
fd = socket(domain, type | SOCK_CLOEXEC, protocol);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
if (errno != EINVAL)
|
||||
return -1;
|
||||
|
||||
fd = socket(domain, type, protocol);
|
||||
return set_cloexec_or_close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
wl_os_dupfd_cloexec(int fd, long minfd)
|
||||
{
|
||||
int newfd;
|
||||
|
||||
newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
|
||||
if (newfd >= 0)
|
||||
return newfd;
|
||||
if (errno != EINVAL)
|
||||
return -1;
|
||||
|
||||
newfd = fcntl(fd, F_DUPFD, minfd);
|
||||
return set_cloexec_or_close(newfd);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
ssize_t len;
|
||||
struct cmsghdr *cmsg;
|
||||
unsigned char *data;
|
||||
int *fd;
|
||||
int *end;
|
||||
|
||||
len = recvmsg(sockfd, msg, flags);
|
||||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if (!msg->msg_control || msg->msg_controllen == 0)
|
||||
return len;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(msg);
|
||||
for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS)
|
||||
continue;
|
||||
|
||||
data = CMSG_DATA(cmsg);
|
||||
end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
|
||||
for (fd = (int *)data; fd < end; ++fd)
|
||||
*fd = set_cloexec_or_close(*fd);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
|
||||
if (len >= 0)
|
||||
return len;
|
||||
if (errno != EINVAL)
|
||||
return -1;
|
||||
|
||||
return recvmsg_cloexec_fallback(sockfd, msg, flags);
|
||||
}
|
||||
|
||||
int
|
||||
wl_os_epoll_create_cloexec(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef EPOLL_CLOEXEC
|
||||
fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
if (errno != EINVAL)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
fd = socket(domain, type, protocol);
|
||||
fd = epoll_create(1);
|
||||
return set_cloexec_or_close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef HAVE_ACCEPT4
|
||||
fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
if (errno != ENOSYS)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
fd = accept(sockfd, addr, addrlen);
|
||||
return set_cloexec_or_close(fd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,4 +26,38 @@
|
|||
int
|
||||
wl_os_socket_cloexec(int domain, int type, int protocol);
|
||||
|
||||
int
|
||||
wl_os_dupfd_cloexec(int fd, long minfd);
|
||||
|
||||
ssize_t
|
||||
wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
|
||||
|
||||
int
|
||||
wl_os_epoll_create_cloexec(void);
|
||||
|
||||
int
|
||||
wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
|
||||
/*
|
||||
* The following are for wayland-os.c and the unit tests.
|
||||
* Do not use them elsewhere.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#ifndef SOCK_CLOEXEC
|
||||
#define SOCK_CLOEXEC 02000000
|
||||
#endif
|
||||
|
||||
#ifndef F_DUPFD_CLOEXEC
|
||||
#define F_DUPFD_CLOEXEC 1030
|
||||
#endif
|
||||
|
||||
#ifndef MSG_CMSG_CLOEXEC
|
||||
#define MSG_CMSG_CLOEXEC 0x40000000
|
||||
#endif
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -902,18 +902,12 @@ socket_data(int fd, uint32_t mask, void *data)
|
|||
int client_fd;
|
||||
|
||||
length = sizeof name;
|
||||
client_fd =
|
||||
accept4(fd, (struct sockaddr *) &name, &length, SOCK_CLOEXEC);
|
||||
if (client_fd < 0 && errno == ENOSYS) {
|
||||
client_fd = accept(fd, (struct sockaddr *) &name, &length);
|
||||
if (client_fd >= 0 && fcntl(client_fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
fprintf(stderr, "failed to set FD_CLOEXEC flag on client fd, errno: %d\n", errno);
|
||||
}
|
||||
|
||||
client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
|
||||
&length);
|
||||
if (client_fd < 0)
|
||||
fprintf(stderr, "failed to accept, errno: %d\n", errno);
|
||||
|
||||
wl_client_create(display, client_fd);
|
||||
else
|
||||
wl_client_create(display, client_fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
|
|
@ -26,40 +27,103 @@
|
|||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "../src/wayland-private.h"
|
||||
#include "test-runner.h"
|
||||
#include "../src/wayland-os.h"
|
||||
|
||||
static int fall_back;
|
||||
static int wrapped_calls;
|
||||
|
||||
static int (*real_socket)(int, int, int);
|
||||
static int wrapped_calls_socket;
|
||||
|
||||
static int (*real_fcntl)(int, int, ...);
|
||||
static int wrapped_calls_fcntl;
|
||||
|
||||
static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
|
||||
static int wrapped_calls_recvmsg;
|
||||
|
||||
static int (*real_epoll_create1)(int);
|
||||
static int wrapped_calls_epoll_create1;
|
||||
|
||||
static void
|
||||
init_fallbacks(int do_fallbacks)
|
||||
{
|
||||
fall_back = do_fallbacks;
|
||||
real_socket = dlsym(RTLD_NEXT, "socket");
|
||||
real_fcntl = dlsym(RTLD_NEXT, "fcntl");
|
||||
real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
|
||||
real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1");
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default"))) int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
wrapped_calls++;
|
||||
wrapped_calls_socket++;
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
if (fall_back && (type & SOCK_CLOEXEC)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return real_socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default"))) int
|
||||
fcntl(int fd, int cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void *arg;
|
||||
|
||||
wrapped_calls_fcntl++;
|
||||
|
||||
if (fall_back && (cmd == F_DUPFD_CLOEXEC)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, void*);
|
||||
va_end(ap);
|
||||
|
||||
return real_fcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default"))) ssize_t
|
||||
recvmsg(int sockfd, struct msghdr *msg, int flags)
|
||||
{
|
||||
wrapped_calls_recvmsg++;
|
||||
|
||||
if (fall_back && (flags & MSG_CMSG_CLOEXEC)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return real_recvmsg(sockfd, msg, flags);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default"))) int
|
||||
epoll_create1(int flags)
|
||||
{
|
||||
wrapped_calls_epoll_create1++;
|
||||
|
||||
if (fall_back) {
|
||||
wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return real_epoll_create1(flags);
|
||||
}
|
||||
|
||||
static void
|
||||
do_os_wrappers_socket_cloexec(int n)
|
||||
{
|
||||
|
|
@ -70,17 +134,13 @@ do_os_wrappers_socket_cloexec(int n)
|
|||
|
||||
/* simply create a socket that closes on exec */
|
||||
fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
|
||||
assert(fd >= 0);
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
/*
|
||||
* Must have 2 calls if falling back, but must also allow
|
||||
* falling back without a forced fallback.
|
||||
*/
|
||||
assert(wrapped_calls > n);
|
||||
#else
|
||||
assert(wrapped_calls == 1);
|
||||
#endif
|
||||
assert(fd >= 0);
|
||||
assert(wrapped_calls_socket > n);
|
||||
|
||||
exec_fd_leak_check(nr_fds);
|
||||
}
|
||||
|
|
@ -98,3 +158,229 @@ TEST(os_wrappers_socket_cloexec_fallback)
|
|||
init_fallbacks(1);
|
||||
do_os_wrappers_socket_cloexec(1);
|
||||
}
|
||||
|
||||
static void
|
||||
do_os_wrappers_dupfd_cloexec(int n)
|
||||
{
|
||||
int base_fd;
|
||||
int fd;
|
||||
int nr_fds;
|
||||
|
||||
nr_fds = count_open_fds();
|
||||
|
||||
base_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
assert(base_fd >= 0);
|
||||
|
||||
fd = wl_os_dupfd_cloexec(base_fd, 13);
|
||||
assert(fd >= 13);
|
||||
|
||||
close(base_fd);
|
||||
|
||||
/*
|
||||
* Must have 4 calls if falling back, but must also allow
|
||||
* falling back without a forced fallback.
|
||||
*/
|
||||
assert(wrapped_calls_fcntl > n);
|
||||
|
||||
exec_fd_leak_check(nr_fds);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_dupfd_cloexec)
|
||||
{
|
||||
init_fallbacks(0);
|
||||
do_os_wrappers_dupfd_cloexec(0);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_dupfd_cloexec_fallback)
|
||||
{
|
||||
init_fallbacks(1);
|
||||
do_os_wrappers_dupfd_cloexec(3);
|
||||
}
|
||||
|
||||
struct marshal_data {
|
||||
struct wl_connection *read_connection;
|
||||
struct wl_connection *write_connection;
|
||||
int s[2];
|
||||
uint32_t read_mask;
|
||||
uint32_t write_mask;
|
||||
union {
|
||||
int h[3];
|
||||
} value;
|
||||
int nr_fds_begin;
|
||||
int nr_fds_conn;
|
||||
int wrapped_calls;
|
||||
};
|
||||
|
||||
static int
|
||||
update_func(struct wl_connection *connection, uint32_t mask, void *data)
|
||||
{
|
||||
uint32_t *m = data;
|
||||
|
||||
*m = mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_marshal_data(struct marshal_data *data)
|
||||
{
|
||||
assert(socketpair(AF_UNIX,
|
||||
SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
|
||||
|
||||
data->read_connection =
|
||||
wl_connection_create(data->s[0],
|
||||
update_func, &data->read_mask);
|
||||
assert(data->read_connection);
|
||||
assert(data->read_mask == WL_CONNECTION_READABLE);
|
||||
|
||||
data->write_connection =
|
||||
wl_connection_create(data->s[1],
|
||||
update_func, &data->write_mask);
|
||||
assert(data->write_connection);
|
||||
assert(data->write_mask == WL_CONNECTION_READABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_demarshal(struct marshal_data *data,
|
||||
void (*func)(void), int size, const char *format, ...)
|
||||
{
|
||||
struct wl_closure closure;
|
||||
static const int opcode = 4444;
|
||||
static struct wl_object sender = { NULL, NULL, 1234 };
|
||||
struct wl_message message = { "test", format, NULL };
|
||||
struct wl_map objects;
|
||||
struct wl_object object;
|
||||
va_list ap;
|
||||
uint32_t msg[1] = { 1234 };
|
||||
int ret;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = wl_closure_vmarshal(&closure, &sender, opcode, ap, &message);
|
||||
va_end(ap);
|
||||
|
||||
assert(ret == 0);
|
||||
assert(wl_closure_send(&closure, data->write_connection) == 0);
|
||||
wl_closure_destroy(&closure);
|
||||
assert(data->write_mask ==
|
||||
(WL_CONNECTION_WRITABLE | WL_CONNECTION_READABLE));
|
||||
assert(wl_connection_data(data->write_connection,
|
||||
WL_CONNECTION_WRITABLE) == 0);
|
||||
assert(data->write_mask == WL_CONNECTION_READABLE);
|
||||
|
||||
assert(wl_connection_data(data->read_connection,
|
||||
WL_CONNECTION_READABLE) == size);
|
||||
|
||||
wl_map_init(&objects);
|
||||
object.id = msg[0];
|
||||
ret = wl_connection_demarshal(data->read_connection,
|
||||
&closure, size, &objects, &message);
|
||||
wl_closure_invoke(&closure, &object, func, data);
|
||||
wl_closure_destroy(&closure);
|
||||
}
|
||||
|
||||
static void
|
||||
validate_recvmsg_h(struct marshal_data *data,
|
||||
struct wl_object *object, int fd1, int fd2, int fd3)
|
||||
{
|
||||
struct stat buf1, buf2;
|
||||
|
||||
assert(fd1 >= 0);
|
||||
assert(fd2 >= 0);
|
||||
assert(fd3 >= 0);
|
||||
|
||||
assert(fd1 != data->value.h[0]);
|
||||
assert(fd2 != data->value.h[1]);
|
||||
assert(fd3 != data->value.h[2]);
|
||||
|
||||
assert(fstat(fd3, &buf1) == 0);
|
||||
assert(fstat(data->value.h[2], &buf2) == 0);
|
||||
assert(buf1.st_dev == buf2.st_dev);
|
||||
assert(buf1.st_ino == buf2.st_ino);
|
||||
|
||||
/* close the original file descriptors */
|
||||
close(data->value.h[0]);
|
||||
close(data->value.h[1]);
|
||||
close(data->value.h[2]);
|
||||
|
||||
/* the dup'd (received) fds should still be open */
|
||||
assert(count_open_fds() == data->nr_fds_conn + 3);
|
||||
|
||||
/*
|
||||
* Must have 2 calls if falling back, but must also allow
|
||||
* falling back without a forced fallback.
|
||||
*/
|
||||
assert(wrapped_calls_recvmsg > data->wrapped_calls);
|
||||
|
||||
if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1)
|
||||
printf("recvmsg fell back unforced.\n");
|
||||
|
||||
/* all fds opened during the test in any way should be gone on exec */
|
||||
exec_fd_leak_check(data->nr_fds_begin);
|
||||
}
|
||||
|
||||
static void
|
||||
do_os_wrappers_recvmsg_cloexec(int n)
|
||||
{
|
||||
struct marshal_data data;
|
||||
|
||||
data.nr_fds_begin = count_open_fds();
|
||||
data.wrapped_calls = n;
|
||||
|
||||
setup_marshal_data(&data);
|
||||
data.nr_fds_conn = count_open_fds();
|
||||
|
||||
assert(pipe(data.value.h) >= 0);
|
||||
|
||||
data.value.h[2] = open("/dev/zero", O_RDONLY);
|
||||
assert(data.value.h[2] >= 0);
|
||||
|
||||
marshal_demarshal(&data, (void *) validate_recvmsg_h,
|
||||
8, "hhh", data.value.h[0], data.value.h[1],
|
||||
data.value.h[2]);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_recvmsg_cloexec)
|
||||
{
|
||||
init_fallbacks(0);
|
||||
do_os_wrappers_recvmsg_cloexec(0);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_recvmsg_cloexec_fallback)
|
||||
{
|
||||
init_fallbacks(1);
|
||||
do_os_wrappers_recvmsg_cloexec(1);
|
||||
}
|
||||
|
||||
static void
|
||||
do_os_wrappers_epoll_create_cloexec(int n)
|
||||
{
|
||||
int fd;
|
||||
int nr_fds;
|
||||
|
||||
nr_fds = count_open_fds();
|
||||
|
||||
fd = wl_os_epoll_create_cloexec();
|
||||
assert(fd >= 0);
|
||||
|
||||
#ifdef EPOLL_CLOEXEC
|
||||
assert(wrapped_calls_epoll_create1 == n);
|
||||
#else
|
||||
printf("No epoll_create1.\n");
|
||||
#endif
|
||||
|
||||
exec_fd_leak_check(nr_fds);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_epoll_create_cloexec)
|
||||
{
|
||||
init_fallbacks(0);
|
||||
do_os_wrappers_epoll_create_cloexec(1);
|
||||
}
|
||||
|
||||
TEST(os_wrappers_epoll_create_cloexec_fallback)
|
||||
{
|
||||
init_fallbacks(1);
|
||||
do_os_wrappers_epoll_create_cloexec(2);
|
||||
}
|
||||
|
||||
/* FIXME: add tests for wl_os_accept_cloexec() */
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ FAIL_TEST(sanity_fd_leak)
|
|||
int fd[2];
|
||||
|
||||
/* leak 2 file descriptors */
|
||||
pipe(fd);
|
||||
if (pipe(fd) < 0)
|
||||
exit(EXIT_SUCCESS); /* failed to fail */
|
||||
}
|
||||
|
||||
FAIL_TEST(sanity_fd_leak_exec)
|
||||
|
|
@ -100,7 +101,8 @@ FAIL_TEST(sanity_fd_leak_exec)
|
|||
int nr_fds = count_open_fds();
|
||||
|
||||
/* leak 2 file descriptors */
|
||||
pipe(fd);
|
||||
if (pipe(fd) < 0)
|
||||
exit(EXIT_SUCCESS); /* failed to fail */
|
||||
|
||||
exec_fd_leak_check(nr_fds);
|
||||
}
|
||||
|
|
@ -111,7 +113,7 @@ TEST(sanity_fd_exec)
|
|||
int nr_fds = count_open_fds();
|
||||
|
||||
/* create 2 file descriptors, that should pass over exec */
|
||||
pipe(fd);
|
||||
assert(pipe(fd) >= 0);
|
||||
|
||||
exec_fd_leak_check(nr_fds + 2);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue