From: Paul Floyd Date: Sat, 16 Sep 2023 14:06:12 +0000 (+0200) Subject: FreeBSD: add wrapperd for timerfd_create timerfd_gettime and timerfd_settime for... X-Git-Tag: VALGRIND_3_22_0~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=adf7cb52eec50749184f95389901e9090befa031;p=thirdparty%2Fvalgrind.git FreeBSD: add wrapperd for timerfd_create timerfd_gettime and timerfd_settime for FreeBSD 15 Mostly copied from the Linux implementation. Add a testcase and a scalar for FreeBSD 15 --- diff --git a/.gitignore b/.gitignore index 48730f2193..0a9f2d3f13 100644 --- a/.gitignore +++ b/.gitignore @@ -1373,6 +1373,7 @@ /memcheck/tests/freebsd/revoke /memcheck/tests/freebsd/scalar /memcheck/tests/freebsd/scalar_13_plus +/memcheck/tests/freebsd/scalar_15_plus /memcheck/tests/freebsd/scalar_abort2 /memcheck/tests/freebsd/scalar_fork /memcheck/tests/freebsd/scalar_pdfork @@ -1385,6 +1386,7 @@ /memcheck/tests/freebsd/stat /memcheck/tests/freebsd/statfs /memcheck/tests/freebsd/static_allocs +/memcheck/tests/freebsd/timerfd /memcheck/tests/freebsd/utimens /memcheck/tests/freebsd/utimes diff --git a/configure.ac b/configure.ac index d745497e80..d1b82c05d2 100755 --- a/configure.ac +++ b/configure.ac @@ -4778,17 +4778,19 @@ fi # test "$VGCONF_OS" = "solaris" #---------------------------------------------------------------------------- # Rather than having a large number of feature test as above with Solaris -# these tests are per-version. This may not be entirely relialable for +# these tests are per-version. This may not be entirely reliable for # FreeBSD development branches (XX.Y-CURRENT) or pre-release branches # (XX.Y-STABLE) but it should work for XX-Y-RELEASE if test "$VGCONF_OS" = "freebsd" ; then AM_CONDITIONAL(FREEBSD_VERS_13_PLUS, test $freebsd_vers -ge $freebsd_13_0) +AM_CONDITIONAL(FREEBSD_VERS_15_PLUS, test $freebsd_vers -ge $freebsd_15) else AM_CONDITIONAL(FREEBSD_VERS_13_PLUS, false) +AM_CONDITIONAL(FREEBSD_VERS_15_PLUS, false) fi # test "$VGCONF_OS" = "freebsd" diff --git a/coregrind/m_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h index 844da82a45..79e52b9fdf 100644 --- a/coregrind/m_syswrap/priv_syswrap-freebsd.h +++ b/coregrind/m_syswrap/priv_syswrap-freebsd.h @@ -556,11 +556,19 @@ DECL_TEMPLATE(freebsd, sys___specialfd) // 577 #if (FREEBSD_VERS >= FREEBSD_13_1) -// unimpl __NR_fspacectl 580 +// unimpl __NR_fspacectl 580 // unimpl __NR_sched_getcpu 581 DECL_TEMPLATE(freebsd, sys_swapoff) // 582 #endif +#if (FREEBSD_VERS >= FREEBSD_15) +// unimpl __NR_kqueuex 583 +// unimpl __NR_membarrier 584 +DECL_TEMPLATE(freebsd, sys_timerfd_create); // 585 +DECL_TEMPLATE(freebsd, sys_timerfd_gettime); // 586 +DECL_TEMPLATE(freebsd, sys_timerfd_settime); // 587 +#endif + DECL_TEMPLATE(freebsd, sys_fake_sigreturn) #endif // PRIV_SYSWRAP_FREEBSD_H diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c index ae11d2a78c..ffe12ef799 100644 --- a/coregrind/m_syswrap/syswrap-freebsd.c +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -6776,6 +6776,86 @@ PRE(sys_swapoff) #endif +#if (FREEBSD_VERS >= FREEBSD_15) + +// SYS_kqueuex 583 unimpl + +// SYS_membarrier 584 unimpl + +// SYS_timerfd_create 585 +// int timerfd_create(int clockid, int flags); +PRE(sys_timerfd_create) +{ + PRINT("sys_timerfd_create (%ld, %ld )", SARG1, SARG2); + PRE_REG_READ2(int, "timerfd_create", int, clockid, int, flags); +} + +POST(sys_timerfd_create) +{ + if (!ML_(fd_allowed)(RES, "timerfd_create", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless) (tid, RES); + } +} + +// SYS_timerfd_gettime 586 +// int timerfd_gettime(int fd, struct itimerspec *curr_value); +PRE(sys_timerfd_gettime) +{ + PRINT("sys_timerfd_gettime ( %ld, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "timerfd_gettime", + int, fd, + struct vki_itimerspec*, curr_value); + if (!ML_(fd_allowed)(ARG1, "timerfd_gettime", tid, False)) + SET_STATUS_Failure(VKI_EBADF); + else + PRE_MEM_WRITE("timerfd_gettime(curr_value)", + ARG2, sizeof(struct vki_itimerspec)); +} + +POST(sys_timerfd_gettime) +{ + if (RES == 0) + POST_MEM_WRITE(ARG2, sizeof(struct vki_itimerspec)); +} + +// SYS_timerfd_gettime 587 +// int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, +// struct itimerspec *old_value); +PRE(sys_timerfd_settime) +{ + PRINT("sys_timerfd_settime(%" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" + FMT_REGWORD "x )", SARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(int, "timerfd_settime", + int, fd, + int, flags, + const struct vki_itimerspec*, new_value, + struct vki_itimerspec*, old_value); + if (!ML_(fd_allowed)(ARG1, "timerfd_settime", tid, False)) + SET_STATUS_Failure(VKI_EBADF); + else + { + PRE_MEM_READ("timerfd_settime(new_value)", + ARG3, sizeof(struct vki_itimerspec)); + if (ARG4) + { + PRE_MEM_WRITE("timerfd_settime(old_value)", + ARG4, sizeof(struct vki_itimerspec)); + } + } +} + +POST(sys_timerfd_settime) +{ + if (RES == 0 && ARG4 != 0) { + POST_MEM_WRITE(ARG4, sizeof(struct vki_itimerspec)); + } +} +#endif + #undef PRE #undef POST @@ -7494,6 +7574,15 @@ const SyscallTableEntry ML_(syscall_table)[] = { BSDX_(__NR_swapoff, sys_swapoff), // 582 #endif +#if (FREEBSD_VERS >= FREEBSD_15) + // unimpl __NR_kqueuex 583 + // unimpl __NR_kqueuex 584 + BSDXY(__NR_timerfd_create, sys_timerfd_create), // 585 + BSDXY(__NR_timerfd_settime, sys_timerfd_settime), // 586 + BSDXY(__NR_timerfd_gettime, sys_timerfd_gettime), // 587 +#endif + + BSDX_(__NR_fake_sigreturn, sys_fake_sigreturn), // 1000, fake sigreturn }; diff --git a/include/vki/vki-scnums-freebsd.h b/include/vki/vki-scnums-freebsd.h index 12ce610007..9eb73591fa 100644 --- a/include/vki/vki-scnums-freebsd.h +++ b/include/vki/vki-scnums-freebsd.h @@ -672,6 +672,16 @@ #endif +#if (FREEBSD_VERS >= FREEBSD_15) + +#define __NR_kqueuex 583 +#define __NR_membarrier 584 +#define __NR_timerfd_create 585 +#define __NR_timerfd_gettime 586 +#define __NR_timerfd_settime 587 + +#endif + #define __NR_fake_sigreturn 1000 #endif /* VKI_UNISTD_FREEBSD_H */ diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index ef6cedc03c..f5b8386c67 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -20,18 +20,33 @@ EXTRA_DIST = \ chmod_chown.vgtest \ chmod_chown.stderr.exp \ close_range.vgtest close_range.stderr.exp \ + errno_aligned_allocs.vgtest \ + errno_aligned_allocs.stderr.exp \ eventfd1.vgtest \ eventfd1.stderr.exp eventfd1.stdout.exp \ eventfd2.vgtest \ eventfd2.stderr.exp \ extattr.vgtest \ extattr.stderr.exp \ + fexecve.vgtest \ + fexecve.stderr.exp \ + file_locking_wait6.vgtest \ + file_locking_wait6.stderr.exp \ + get_set_context.vgtest \ + get_set_context.stderr.exp \ + get_set_context.stderr.exp-x86 \ get_set_login.vgtest \ get_set_login.stderr.exp \ + getfh.vgtest \ + getfh.stderr.exp \ getfsstat.vgtest \ getfsstat.stderr.exp \ getfsstat.supp \ getfsstat.stderr.exp-x86 \ + linkat.vgtest \ + linkat.stderr.exp \ + misc.vgtest \ + misc.stderr.exp \ pdfork_pdkill.vgtest \ pdfork_pdkill.stderr.exp \ revoke.vgtest \ @@ -58,35 +73,25 @@ EXTRA_DIST = \ supponlyobj.vgtest \ supponlyobj.stderr.exp \ supponlyobj.supp \ - getfh.vgtest \ - getfh.stderr.exp \ - linkat.vgtest \ - linkat.stderr.exp \ stat.vgtest \ stat.stderr.exp \ stat.stderr.exp-x86 \ - file_locking_wait6.vgtest \ - file_locking_wait6.stderr.exp \ + timerfd.vgtest \ + timerfd.stderr.exp \ + timerfd.stdout.exp \ utimens.vgtest \ utimens.stderr.exp \ - misc.vgtest \ - misc.stderr.exp \ - get_set_context.vgtest \ - get_set_context.stderr.exp \ - get_set_context.stderr.exp-x86 \ utimes.vgtest \ utimes.stderr.exp-x86 \ utimes.stderr.exp \ static_allocs.vgtest \ static_allocs.stderr.exp \ - fexecve.vgtest \ - fexecve.stderr.exp \ realpathat.vgtest \ realpathat.stderr.exp \ scalar_13_plus.vgtest \ scalar_13_plus.stderr.exp \ - errno_aligned_allocs.vgtest \ - errno_aligned_allocs.stderr.exp \ + scalar_15_plus.vgtest \ + scalar_15_plus.stderr.exp \ setproctitle.vgtest \ setproctitle.stderr.exp \ setproctitle.stdout.exp \ @@ -140,10 +145,15 @@ bug470713_SOURCES = bug470713.cpp if FREEBSD_VERS_13_PLUS check_PROGRAMS += realpathat scalar_13_plus eventfd1 eventfd2 - scalar_13_plus_CFLAGS = ${AM_CFLAGS} -g endif +if FREEBSD_VERS_15_PLUS +check_PROGRAMS += scalar_15_plus timerfd +scalar_15_plus_CFLAGS = ${AM_CFLAGS} -g +timerfd_LDFLAGS = -lm +endif + if HAVE_CLOSE_RANGE check_PROGRAMS += close_range endif diff --git a/memcheck/tests/freebsd/scalar_15_plus.c b/memcheck/tests/freebsd/scalar_15_plus.c new file mode 100644 index 0000000000..cd40a20460 --- /dev/null +++ b/memcheck/tests/freebsd/scalar_15_plus.c @@ -0,0 +1,29 @@ +#include "scalar.h" +#include + +int main(void) +{ + long *px = malloc(2*sizeof(long)); + x0 = px[0]; + + /* SYS_kqueuex 583 */ + /* unimpl */ + + /* SYS_membarrier 584 */ + /* unimpl */ + + /* SYS_timerfd_create 585 */ + GO(SYS_timerfd_create, " 2s 0m"); + SY(SYS_timerfd_create, x0+123, x0+23456); FAIL; + + /* SYS_timerfd_gettime 586 */ + GO(SYS_timerfd_gettime, " 2s 1m"); + SY(SYS_timerfd_gettime, x0+100, x0); FAIL; + + /* SYS_timerfd_settime 587 */ + GO(SYS_timerfd_settime, "3s 2m"); + SY(SYS_timerfd_settime, x0+321, x0, x0+10); FAIL; + + return(0); +} + diff --git a/memcheck/tests/freebsd/scalar_15_plus.stderr.exp b/memcheck/tests/freebsd/scalar_15_plus.stderr.exp new file mode 100644 index 0000000000..6c2ef077c4 --- /dev/null +++ b/memcheck/tests/freebsd/scalar_15_plus.stderr.exp @@ -0,0 +1,43 @@ +--------------------------------------------------------- +585: SYS_timerfd_create 2s 0m +--------------------------------------------------------- +Syscall param timerfd_create(clockid) contains uninitialised byte(s) + ... + +Syscall param timerfd_create(flags) contains uninitialised byte(s) + ... + +--------------------------------------------------------- +586: SYS_timerfd_gettime 2s 1m +--------------------------------------------------------- +Syscall param timerfd_gettime(fd) contains uninitialised byte(s) + ... + +Syscall param timerfd_gettime(curr_value) contains uninitialised byte(s) + ... + +Syscall param timerfd_gettime(curr_value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +--------------------------------------------------------- +587: SYS_timerfd_settime 3s 2m +--------------------------------------------------------- +Syscall param timerfd_settime(fd) contains uninitialised byte(s) + ... + +Syscall param timerfd_settime(flags) contains uninitialised byte(s) + ... + +Syscall param timerfd_settime(new_value) contains uninitialised byte(s) + ... + +Syscall param timerfd_settime(new_value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +Syscall param timerfd_settime(old_value) points to unaddressable byte(s) + ... + Address 0x........ is on thread 1's stack + .... bytes below stack pointer + diff --git a/memcheck/tests/freebsd/scalar_15_plus.vgtest b/memcheck/tests/freebsd/scalar_15_plus.vgtest new file mode 100644 index 0000000000..fe40176591 --- /dev/null +++ b/memcheck/tests/freebsd/scalar_15_plus.vgtest @@ -0,0 +1,12 @@ +prereq: test -e ./scalar_15_plus +prog: scalar_15_plus +vgopts: -q --error-limit=no +stderr_filter: filter_scalar +# Remove all frames from the stack trace except the first one. +# This is important because syscall() function on x86 isn't ABI conformant +# which confuses the Valgrind stack unwinder. +# Therefore x86 and amd64 stack traces are unified so that they contain only +# 'syscall (in libc)' stack frame and this is then filtered out completely. +stderr_filter_args: libc +args: < scalar_13_plus.c + diff --git a/memcheck/tests/freebsd/timerfd.c b/memcheck/tests/freebsd/timerfd.c new file mode 100644 index 0000000000..7ed964cc9b --- /dev/null +++ b/memcheck/tests/freebsd/timerfd.c @@ -0,0 +1,150 @@ +/* Copied from the Linux manpage + * with the printed times rounded to + * seconds for reproducibility. + * And some errors added. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../memcheck.h" + +static void +print_elapsed_time(void) +{ + int secs, nsecs; + static int first_call = 1; + struct timespec curr; + static struct timespec start; + int round_secs; + + if (first_call) { + first_call = 0; + if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) + err(EXIT_FAILURE, "clock_gettime"); + } + + if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) + err(EXIT_FAILURE, "clock_gettime"); + + secs = curr.tv_sec - start.tv_sec; + nsecs = curr.tv_nsec - start.tv_nsec; + if (nsecs < 0) { + secs--; + nsecs += 1000000000; + } + round_secs = round((secs*1e9 + nsecs)/1e9); + printf("%d: ", round_secs); +} + +int +main(int argc, char *argv[]) +{ + int fd; + ssize_t s; + uint64_t exp, tot_exp, max_exp; + struct timespec now; + struct itimerspec new_value; + + if (argc != 2 && argc != 4) { + fprintf(stderr, "%s init-secs [interval-secs max-exp]\n", + argv[0]); + exit(EXIT_FAILURE); + } + + if (clock_gettime(CLOCK_REALTIME, &now) == -1) + err(EXIT_FAILURE, "clock_gettime"); + + /* Create a CLOCK_REALTIME absolute timer with initial + expiration and interval as specified in command line. */ + + new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]); + new_value.it_value.tv_nsec = now.tv_nsec; + if (argc == 2) { + new_value.it_interval.tv_sec = 0; + max_exp = 1; + } else { + new_value.it_interval.tv_sec = atoi(argv[2]); + max_exp = atoi(argv[3]); + } + new_value.it_interval.tv_nsec = 0; + + fd = timerfd_create(CLOCK_REALTIME, 0); + if (fd == -1) + err(EXIT_FAILURE, "timerfd_create"); + + if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1) + err(EXIT_FAILURE, "timerfd_settime"); + + print_elapsed_time(); + printf("timer started\n"); + + for (tot_exp = 0; tot_exp < max_exp;) { + s = read(fd, &exp, sizeof(uint64_t)); + if (s != sizeof(uint64_t)) + err(EXIT_FAILURE, "read"); + + tot_exp += exp; + print_elapsed_time(); + printf("read: %" PRIu64 "; total=%" PRIu64 "\n", exp, tot_exp); + } + + close(fd); + + { + int a = CLOCK_REALTIME; + int b = TFD_CLOEXEC; + int c = TFD_TIMER_ABSTIME; + VALGRIND_MAKE_MEM_UNDEFINED(&a, sizeof(a)); + VALGRIND_MAKE_MEM_UNDEFINED(&b, sizeof(b)); + VALGRIND_MAKE_MEM_UNDEFINED(&c, sizeof(c)); + struct itimerspec * get_ts = malloc(sizeof(*get_ts) - 2); + struct itimerspec * set_ts = malloc(sizeof(*set_ts) - 2); + struct itimerspec ts; + int retval; + + errno = 0; + /* uninit clockid and flag but should work */ + int fd2 = timerfd_create(a, b); + assert(fd2 != -1); + assert(errno == 0); + /* bad flag should fail */ + timerfd_create(CLOCK_REALTIME, 1000000); + /* bad clockid should fail */ + timerfd_create(1000000, TFD_CLOEXEC); + + /* memory too small for requested get */ + timerfd_gettime(fd2, get_ts); + /* should succeed */ + timerfd_gettime(fd2, &ts); + ts.it_interval.tv_nsec += 100000; + + /* uninit flag */ + timerfd_settime(fd2, c, &ts, NULL); + errno = 0; + ts.it_interval.tv_nsec += 100000; + /* memory too small for requested old value */ + retval = timerfd_settime(fd2, TFD_TIMER_ABSTIME, &ts, set_ts); + assert(retval == 0); + assert(errno == 0); + + VALGRIND_MAKE_MEM_UNDEFINED(&fd2, sizeof(fd2)); + timerfd_gettime(fd2, &ts); + ts.it_interval.tv_nsec += 100000; + timerfd_settime(fd2, TFD_TIMER_ABSTIME, &ts, NULL); + + + free(get_ts); + free(set_ts); + } + + exit(EXIT_SUCCESS); +} + diff --git a/memcheck/tests/freebsd/timerfd.stderr.exp b/memcheck/tests/freebsd/timerfd.stderr.exp new file mode 100644 index 0000000000..4831ec8061 --- /dev/null +++ b/memcheck/tests/freebsd/timerfd.stderr.exp @@ -0,0 +1,40 @@ +Syscall param timerfd_create(clockid) contains uninitialised byte(s) + at 0x........: timerfd_create (in /...libc...) + by 0x........: main (timerfd.c:115) + +Syscall param timerfd_create(flags) contains uninitialised byte(s) + at 0x........: timerfd_create (in /...libc...) + by 0x........: main (timerfd.c:115) + +Syscall param timerfd_gettime(curr_value) points to unaddressable byte(s) + at 0x........: timerfd_gettime (in /...libc...) + by 0x........: main (timerfd.c:124) + Address 0x........ is 0 bytes after a block of size 30 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (timerfd.c:108) + +Syscall param timerfd_settime(flags) contains uninitialised byte(s) + at 0x........: timerfd_settime (in /...libc...) + by 0x........: main (timerfd.c:130) + +Syscall param timerfd_settime(old_value) points to unaddressable byte(s) + at 0x........: timerfd_settime (in /...libc...) + by 0x........: main (timerfd.c:134) + Address 0x........ is 0 bytes after a block of size 30 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (timerfd.c:109) + +Syscall param timerfd_gettime(fd) contains uninitialised byte(s) + at 0x........: timerfd_gettime (in /...libc...) + by 0x........: main (timerfd.c:139) + +Syscall param timerfd_settime(fd) contains uninitialised byte(s) + at 0x........: timerfd_settime (in /...libc...) + by 0x........: main (timerfd.c:141) + +FILE DESCRIPTORS: 4 open (3 std) at exit. +Open file descriptor 3: + at 0x........: timerfd_create (in /...libc...) + by 0x........: main (timerfd.c:115) + + diff --git a/memcheck/tests/freebsd/timerfd.stdout.exp b/memcheck/tests/freebsd/timerfd.stdout.exp new file mode 100644 index 0000000000..30ee11e259 --- /dev/null +++ b/memcheck/tests/freebsd/timerfd.stdout.exp @@ -0,0 +1,4 @@ +0: timer started +1: read: 1; total=1 +2: read: 1; total=2 +3: read: 1; total=3 diff --git a/memcheck/tests/freebsd/timerfd.vgtest b/memcheck/tests/freebsd/timerfd.vgtest new file mode 100644 index 0000000000..b71f7b7afd --- /dev/null +++ b/memcheck/tests/freebsd/timerfd.vgtest @@ -0,0 +1,4 @@ +prereq: test -e ./timerfd +prog: timerfd +args: 1 1 3 +vgopts: -q --track-fds=yes