mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05: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-util.h"
 | 
				
			||||||
#include "wayland-private.h"
 | 
					#include "wayland-private.h"
 | 
				
			||||||
 | 
					#include "wayland-os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
 | 
					#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -518,7 +519,7 @@ wl_closure_vmarshal(struct wl_closure *closure,
 | 
				
			||||||
			extra += sizeof *fd_ptr;
 | 
								extra += sizeof *fd_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fd = va_arg(ap, int);
 | 
								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) {
 | 
								if (dup_fd < 0) {
 | 
				
			||||||
				fprintf(stderr, "dup failed: %m");
 | 
									fprintf(stderr, "dup failed: %m");
 | 
				
			||||||
				abort();
 | 
									abort();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,3 +64,18 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
 | 
				
			||||||
	fd = socket(domain, type, protocol);
 | 
						fd = socket(domain, type, protocol);
 | 
				
			||||||
	return set_cloexec_or_close(fd);
 | 
						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
 | 
					int
 | 
				
			||||||
wl_os_socket_cloexec(int domain, int type, int protocol);
 | 
					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.
 | 
					 * The following are for wayland-os.c and the unit tests.
 | 
				
			||||||
 * Do not use them elsewhere.
 | 
					 * Do not use them elsewhere.
 | 
				
			||||||
| 
						 | 
					@ -37,6 +40,10 @@ wl_os_socket_cloexec(int domain, int type, int protocol);
 | 
				
			||||||
#define SOCK_CLOEXEC 02000000
 | 
					#define SOCK_CLOEXEC 02000000
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef F_DUPFD_CLOEXEC
 | 
				
			||||||
 | 
					#define F_DUPFD_CLOEXEC 1030
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __linux__ */
 | 
					#endif /* __linux__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,26 +29,32 @@
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <dlfcn.h>
 | 
					#include <dlfcn.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "test-runner.h"
 | 
					#include "test-runner.h"
 | 
				
			||||||
#include "../src/wayland-os.h"
 | 
					#include "../src/wayland-os.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int fall_back;
 | 
					static int fall_back;
 | 
				
			||||||
static int wrapped_calls;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int (*real_socket)(int, int, int);
 | 
					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
 | 
					static void
 | 
				
			||||||
init_fallbacks(int do_fallbacks)
 | 
					init_fallbacks(int do_fallbacks)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fall_back = do_fallbacks;
 | 
						fall_back = do_fallbacks;
 | 
				
			||||||
	real_socket = dlsym(RTLD_NEXT, "socket");
 | 
						real_socket = dlsym(RTLD_NEXT, "socket");
 | 
				
			||||||
 | 
						real_fcntl = dlsym(RTLD_NEXT, "fcntl");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__attribute__ ((visibility("default"))) int
 | 
					__attribute__ ((visibility("default"))) int
 | 
				
			||||||
socket(int domain, int type, int protocol)
 | 
					socket(int domain, int type, int protocol)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	wrapped_calls++;
 | 
						wrapped_calls_socket++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fall_back && (type & SOCK_CLOEXEC)) {
 | 
						if (fall_back && (type & SOCK_CLOEXEC)) {
 | 
				
			||||||
		errno = EINVAL;
 | 
							errno = EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -58,6 +64,26 @@ socket(int domain, int type, int protocol)
 | 
				
			||||||
	return real_socket(domain, type, 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
 | 
					static void
 | 
				
			||||||
do_os_wrappers_socket_cloexec(int n)
 | 
					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
 | 
						 * Must have 2 calls if falling back, but must also allow
 | 
				
			||||||
	 * falling back without a forced fallback.
 | 
						 * falling back without a forced fallback.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	assert(wrapped_calls > n);
 | 
						assert(wrapped_calls_socket > n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	exec_fd_leak_check(nr_fds);
 | 
						exec_fd_leak_check(nr_fds);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -92,3 +118,41 @@ TEST(os_wrappers_socket_cloexec_fallback)
 | 
				
			||||||
	init_fallbacks(1);
 | 
						init_fallbacks(1);
 | 
				
			||||||
	do_os_wrappers_socket_cloexec(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