Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 64-bit time_t on 32 bit architectures #236

Merged
merged 4 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ add_project_arguments(
cc.get_supported_arguments(
# Vala doesn't have `const void*`, or a way to selectively #pragma these in the code
'-Wno-error=discarded-qualifiers',
# spi_ioc_transfer.[rx]x_buf are pointers, but declared u64 everywhere; Vala can't selectively #pragma these
'-Wno-error=pointer-to-int-cast',
# mostly const dropping and dropped "volatile" in fully autogenerated code;
# upstream Vala does not support fixing this warning
'-Wno-error=incompatible-pointer-types',
Expand Down
90 changes: 87 additions & 3 deletions src/libumockdev-preload.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,30 @@
* along with umockdev; If not, see <http://www.gnu.org/licenses/>.
*/

/* override -D_FILE_OFFSET_BITS, it breaks us */
#undef _FILE_OFFSET_BITS

/* for getting stat64 */
#define _GNU_SOURCE

#include <features.h>

#ifdef __GLIBC__
/* Remove gcc asm aliasing so that our interposed symbols work as expected */
#include <sys/cdefs.h>

#include <stddef.h>
extern int __REDIRECT_NTH (__ttyname_r_alias, (int __fd, char *__buf,
size_t __buflen), ttyname_r);

#ifdef __REDIRECT
#undef __REDIRECT
#endif
#define __REDIRECT(name, proto, alias) name proto
#ifdef __REDIRECT_NTH
#undef __REDIRECT_NTH
#endif
#define __REDIRECT_NTH(name, proto, alias) name proto __THROW

#endif /* __GLIBC__ */

#include <assert.h>
#include <errno.h>
#include <dirent.h>
Expand Down Expand Up @@ -63,6 +81,14 @@
#include "utils.h"
#include "ioctl_tree.h"

#ifdef __GLIBC__
/* Fixup for making a mess with __REDIRECT above */
#ifdef __USE_TIME_BITS64
#define clock_gettime __clock_gettime64
extern int clock_gettime(clockid_t clockid, struct timespec *tp);
#endif
#endif

/* fix missing O_TMPFILE on some systems */
#ifndef O_TMPFILE
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
Expand Down Expand Up @@ -1213,6 +1239,8 @@ rettype name(const char *path, arg2t arg2, arg3t arg3, arg4t arg4) \
* the emulated /dev to indicate a block device (the sticky bit has no
* real functionality for device nodes) */
#define WRAP_STAT(prefix, suffix) \
extern int prefix ## stat ## suffix (const char *path, \
struct stat ## suffix *st); \
int prefix ## stat ## suffix (const char *path, struct stat ## suffix *st) \
{ \
const char *p; \
Expand All @@ -1233,6 +1261,8 @@ int prefix ## stat ## suffix (const char *path, struct stat ## suffix *st) \

/* wrapper template for fstatat family */
#define WRAP_FSTATAT(prefix, suffix) \
extern int prefix ## fstatat ## suffix (int dirfd, const char *path, \
struct stat ## suffix *st, int flags); \
int prefix ## fstatat ## suffix (int dirfd, const char *path, struct stat ## suffix *st, int flags) \
{ \
const char *p; \
Expand Down Expand Up @@ -1390,6 +1420,12 @@ WRAP_STAT(,64);
WRAP_STAT(l,64);
WRAP_FSTATAT(,64);
WRAP_FOPEN(,64);
#if defined(__USE_FILE_OFFSET64) && defined(__USE_TIME_BITS64)
#define stat64_time64 stat64
WRAP_STAT(__,64_time64);
WRAP_STAT(__l,64_time64);
WRAP_FSTATAT(__,64_time64);
#endif
#endif

WRAP_3ARGS(ssize_t, -1, readlink, char *, size_t);
Expand Down Expand Up @@ -1759,6 +1795,18 @@ recvmsg(int sockfd, struct msghdr * msg, int flags)
return ret;
}

extern ssize_t __recvmsg64(int sockfd, struct msghdr * msg, int flags);
ssize_t
__recvmsg64(int sockfd, struct msghdr * msg, int flags)
{
libc_func(__recvmsg64, int, int, struct msghdr *, int);
ssize_t ret = ___recvmsg64(sockfd, msg, flags);

netlink_recvmsg(sockfd, msg, ret);

return ret;
}

int
socket(int domain, int type, int protocol)
{
Expand Down Expand Up @@ -1876,6 +1924,42 @@ ioctl(int d, IOCTL_REQUEST_TYPE request, ...)
return result;
}

#ifdef __GLIBC__

extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW;
int
__ioctl_time64(int d, IOCTL_REQUEST_TYPE request, ...)
{
libc_func(__ioctl_time64, int, int, IOCTL_REQUEST_TYPE, ...);
int result;
va_list ap;
void* arg;

/* one cannot reliably forward arbitrary varargs
* (http://c-faq.com/varargs/handoff.html), but we know that ioctl gets at
* most one extra argument, and almost all of them are pointers or ints,
* both of which fit into a void*.
*/
va_start(ap, request);
arg = va_arg(ap, void*);
va_end(ap);

result = remote_emulate(d, IOCTL_REQ_IOCTL, (unsigned int) request, (long) arg);
if (result != UNHANDLED) {
DBG(DBG_IOCTL, "ioctl fd %i request %X: emulated, result %i\n", d, (unsigned) request, result);
return result;
}

/* fallback to call original ioctl */
result = ___ioctl_time64(d, request, arg);
DBG(DBG_IOCTL, "ioctl fd %i request %X: original, result %i\n", d, (unsigned) request, result);

return result;
}

#endif /* __GLIBC__ */


int
isatty(int fd)
{
Expand Down
1 change: 1 addition & 0 deletions tests/test-umockdev-vala.vala
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ t_spidev_ioctl ()
tx_buf[1] = 0xff;

Posix.memset (xfer, 0, sizeof (Ioctl.spi_ioc_transfer) * 2);
/* these casts are evil, bad, and wrong -- but that's how Linux defines them, even 32 bit platforms have u64 */
xfer[0].tx_buf = (uint64) tx_buf;
xfer[0].len = 2;
xfer[1].rx_buf = (uint64) rx_buf;
Expand Down
5 changes: 5 additions & 0 deletions tests/test-umockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1578,7 +1578,12 @@ t_testbed_script_replay_evdev_event_framing(UMockdevTestbedFixture * fixture, UN
int fd;
char buf[1024];

#if __BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)
struct timeval dummy = {0};
#else
__kernel_ulong_t dummy = 0;
#endif

/* Simple evdev stream - x coordinate followed by SYN, times 2 */
struct input_event dummy_events[] = {
{dummy, 0003, 0000, 2534},
Expand Down