mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-01 22:58:40 -04:00
os: wrap F_DUPFD_CLOEXEC
Some system C libraries do not have F_DUPFD_CLOEXEC. Provide a fallback. Add tests for the new wl_os_dupfd_cloexec() wrapper. Add per-wrapper call counters in os_wrappers-test.c. Makes it easier to determine the minimum required number of wrapped calls. Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
This commit is contained in:
parent
3b29783dc8
commit
1463a41f89
4 changed files with 91 additions and 4 deletions
|
|
@ -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) )
|
||||
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -64,3 +64,18 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
int
|
||||
wl_os_socket_cloexec(int domain, int type, int protocol);
|
||||
|
||||
int
|
||||
wl_os_dupfd_cloexec(int fd, long minfd);
|
||||
|
||||
/*
|
||||
* The following are for wayland-os.c and the unit tests.
|
||||
* Do not use them elsewhere.
|
||||
|
|
@ -37,6 +40,10 @@ wl_os_socket_cloexec(int domain, int type, int protocol);
|
|||
#define SOCK_CLOEXEC 02000000
|
||||
#endif
|
||||
|
||||
#ifndef F_DUPFD_CLOEXEC
|
||||
#define F_DUPFD_CLOEXEC 1030
|
||||
#endif
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,26 +29,32 @@
|
|||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.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 void
|
||||
init_fallbacks(int do_fallbacks)
|
||||
{
|
||||
fall_back = do_fallbacks;
|
||||
real_socket = dlsym(RTLD_NEXT, "socket");
|
||||
real_fcntl = dlsym(RTLD_NEXT, "fcntl");
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("default"))) int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
wrapped_calls++;
|
||||
wrapped_calls_socket++;
|
||||
|
||||
if (fall_back && (type & SOCK_CLOEXEC)) {
|
||||
errno = EINVAL;
|
||||
|
|
@ -58,6 +64,26 @@ socket(int domain, int type, int protocol)
|
|||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
do_os_wrappers_socket_cloexec(int n)
|
||||
{
|
||||
|
|
@ -74,7 +100,7 @@ do_os_wrappers_socket_cloexec(int n)
|
|||
* Must have 2 calls if falling back, but must also allow
|
||||
* falling back without a forced fallback.
|
||||
*/
|
||||
assert(wrapped_calls > n);
|
||||
assert(wrapped_calls_socket > n);
|
||||
|
||||
exec_fd_leak_check(nr_fds);
|
||||
}
|
||||
|
|
@ -92,3 +118,41 @@ 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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue