Mostly copied from the Linux implementation.
Add a testcase and a scalar for FreeBSD 15
/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
/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
#----------------------------------------------------------------------------
# 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"
#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
#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
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
};
#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 */
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 \
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 \
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
--- /dev/null
+#include "scalar.h"
+#include <sys/mman.h>
+
+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);
+}
+
--- /dev/null
+---------------------------------------------------------
+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
+
--- /dev/null
+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
+
--- /dev/null
+/* Copied from the Linux manpage
+ * with the printed times rounded to
+ * seconds for reproducibility.
+ * And some errors added.
+ */
+
+#include <err.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/timerfd.h>
+#include <time.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+#include <assert.h>
+#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);
+}
+
--- /dev/null
+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)
+
+
--- /dev/null
+0: timer started
+1: read: 1; total=1
+2: read: 1; total=2
+3: read: 1; total=3
--- /dev/null
+prereq: test -e ./timerfd
+prog: timerfd
+args: 1 1 3
+vgopts: -q --track-fds=yes