mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-29 05:40:16 -04:00
tests: manually wrap libc functions
The way we're wrapping libc functions via dlsym() is pretty fragile and breaks on FreeBSD. The failures happen in our CI and are pretty random, see e.g. [1]. Use a more manual way to wrap via a function pointer. [1]: https://gitlab.freedesktop.org/wayland/wayland/-/jobs/44204010 Signed-off-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
parent
4a7348e48c
commit
4ec379ebcc
2 changed files with 47 additions and 62 deletions
|
|
@ -42,6 +42,12 @@
|
||||||
|
|
||||||
#include "wayland-os.h"
|
#include "wayland-os.h"
|
||||||
|
|
||||||
|
/* used by tests */
|
||||||
|
int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl;
|
||||||
|
int (*wl_socket)(int domain, int type, int protocol) = socket;
|
||||||
|
ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg;
|
||||||
|
int (*wl_epoll_create1)(int flags) = epoll_create1;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
set_cloexec_or_close(int fd)
|
set_cloexec_or_close(int fd)
|
||||||
{
|
{
|
||||||
|
|
@ -50,11 +56,11 @@ set_cloexec_or_close(int fd)
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
flags = fcntl(fd, F_GETFD);
|
flags = wl_fcntl(fd, F_GETFD);
|
||||||
if (flags == -1)
|
if (flags == -1)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
if (wl_fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
|
|
@ -69,13 +75,13 @@ wl_os_socket_cloexec(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = socket(domain, type | SOCK_CLOEXEC, protocol);
|
fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
if (errno != EINVAL)
|
if (errno != EINVAL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
fd = socket(domain, type, protocol);
|
fd = wl_socket(domain, type, protocol);
|
||||||
return set_cloexec_or_close(fd);
|
return set_cloexec_or_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,13 +130,13 @@ wl_os_dupfd_cloexec(int fd, int minfd)
|
||||||
{
|
{
|
||||||
int newfd;
|
int newfd;
|
||||||
|
|
||||||
newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
|
newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd);
|
||||||
if (newfd >= 0)
|
if (newfd >= 0)
|
||||||
return newfd;
|
return newfd;
|
||||||
if (errno != EINVAL)
|
if (errno != EINVAL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
newfd = fcntl(fd, F_DUPFD, minfd);
|
newfd = wl_fcntl(fd, F_DUPFD, minfd);
|
||||||
return set_cloexec_or_close(newfd);
|
return set_cloexec_or_close(newfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +149,7 @@ recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
|
||||||
int *fd;
|
int *fd;
|
||||||
int *end;
|
int *end;
|
||||||
|
|
||||||
len = recvmsg(sockfd, msg, flags);
|
len = wl_recvmsg(sockfd, msg, flags);
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
@ -179,7 +185,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
|
||||||
#else
|
#else
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
|
len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
|
||||||
if (len >= 0)
|
if (len >= 0)
|
||||||
return len;
|
return len;
|
||||||
if (errno != EINVAL)
|
if (errno != EINVAL)
|
||||||
|
|
@ -194,7 +200,7 @@ wl_os_epoll_create_cloexec(void)
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
#ifdef EPOLL_CLOEXEC
|
#ifdef EPOLL_CLOEXEC
|
||||||
fd = epoll_create1(EPOLL_CLOEXEC);
|
fd = wl_epoll_create1(EPOLL_CLOEXEC);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
if (errno != EINVAL)
|
if (errno != EINVAL)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
@ -45,50 +44,20 @@
|
||||||
#include "test-runner.h"
|
#include "test-runner.h"
|
||||||
#include "wayland-os.h"
|
#include "wayland-os.h"
|
||||||
|
|
||||||
|
extern int (*wl_socket)(int domain, int type, int protocol);
|
||||||
|
extern int (*wl_fcntl)(int fildes, int cmd, ...);
|
||||||
|
extern ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags);
|
||||||
|
extern int (*wl_epoll_create1)(int flags);
|
||||||
|
|
||||||
static int fall_back;
|
static int fall_back;
|
||||||
|
|
||||||
/* Play nice with sanitizers
|
static int wrapped_calls_socket = 0;
|
||||||
*
|
static int wrapped_calls_fcntl = 0;
|
||||||
* Sanitizers need to intercept syscalls in the compiler run-time library. As
|
static int wrapped_calls_recvmsg = 0;
|
||||||
* this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't
|
static int wrapped_calls_epoll_create1 = 0;
|
||||||
* work: there can only be one function named "socket" etc. To support this, the
|
|
||||||
* sanitizer library names its interceptors with the prefix __interceptor_ ("__"
|
|
||||||
* being reserved for the implementation) and then weakly aliases it to the real
|
|
||||||
* function. The functions we define below will override the weak alias, and we
|
|
||||||
* can call them by the __interceptor_ name directly. This allows the sanitizer
|
|
||||||
* to do its work before calling the next version of the function via dlsym.
|
|
||||||
*
|
|
||||||
* However! We also don't know which of these functions the sanitizer actually
|
|
||||||
* wants to override, so we have to declare our own weak symbols for
|
|
||||||
* __interceptor_ and check at run time if they linked to anything or not.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DECL(ret_type, func, ...) \
|
static int
|
||||||
ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \
|
socket_wrapper(int domain, int type, int protocol)
|
||||||
static ret_type (*real_ ## func)(__VA_ARGS__); \
|
|
||||||
static int wrapped_calls_ ## func;
|
|
||||||
|
|
||||||
#define REAL(func) (__interceptor_ ## func) ? \
|
|
||||||
__interceptor_ ## func : \
|
|
||||||
(__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func)
|
|
||||||
|
|
||||||
DECL(int, socket, int, int, int);
|
|
||||||
DECL(int, fcntl, int, int, ...);
|
|
||||||
DECL(ssize_t, recvmsg, int, struct msghdr *, int);
|
|
||||||
DECL(int, epoll_create1, int);
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_fallbacks(int do_fallbacks)
|
|
||||||
{
|
|
||||||
fall_back = do_fallbacks;
|
|
||||||
real_socket = REAL(socket);
|
|
||||||
real_fcntl = REAL(fcntl);
|
|
||||||
real_recvmsg = REAL(recvmsg);
|
|
||||||
real_epoll_create1 = REAL(epoll_create1);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((visibility("default"))) int
|
|
||||||
socket(int domain, int type, int protocol)
|
|
||||||
{
|
{
|
||||||
wrapped_calls_socket++;
|
wrapped_calls_socket++;
|
||||||
|
|
||||||
|
|
@ -97,11 +66,11 @@ socket(int domain, int type, int protocol)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return real_socket(domain, type, protocol);
|
return socket(domain, type, protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((visibility("default"))) int
|
static int
|
||||||
(fcntl)(int fd, int cmd, ...)
|
fcntl_wrapper(int fd, int cmd, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int arg;
|
int arg;
|
||||||
|
|
@ -131,13 +100,13 @@ __attribute__ ((visibility("default"))) int
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_arg) {
|
if (has_arg) {
|
||||||
return real_fcntl(fd, cmd, arg);
|
return fcntl(fd, cmd, arg);
|
||||||
}
|
}
|
||||||
return real_fcntl(fd, cmd);
|
return fcntl(fd, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((visibility("default"))) ssize_t
|
static ssize_t
|
||||||
recvmsg(int sockfd, struct msghdr *msg, int flags)
|
recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags)
|
||||||
{
|
{
|
||||||
wrapped_calls_recvmsg++;
|
wrapped_calls_recvmsg++;
|
||||||
|
|
||||||
|
|
@ -146,11 +115,11 @@ recvmsg(int sockfd, struct msghdr *msg, int flags)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return real_recvmsg(sockfd, msg, flags);
|
return recvmsg(sockfd, msg, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((visibility("default"))) int
|
static int
|
||||||
epoll_create1(int flags)
|
epoll_create1_wrapper(int flags)
|
||||||
{
|
{
|
||||||
wrapped_calls_epoll_create1++;
|
wrapped_calls_epoll_create1++;
|
||||||
|
|
||||||
|
|
@ -160,7 +129,17 @@ epoll_create1(int flags)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return real_epoll_create1(flags);
|
return epoll_create1(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_fallbacks(int do_fallbacks)
|
||||||
|
{
|
||||||
|
fall_back = do_fallbacks;
|
||||||
|
wl_fcntl = fcntl_wrapper;
|
||||||
|
wl_socket = socket_wrapper;
|
||||||
|
wl_recvmsg = recvmsg_wrapper;
|
||||||
|
wl_epoll_create1 = epoll_create1_wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue