From c648b4a832a0913b37128bd27d07df635eafd029 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 18 Sep 2015 14:24:51 +0000 Subject: [PATCH] Fix decoding of clock_nanosleep * time.c (sys_clock_nanosleep): Use is_erestart, temporarily_clear_syserror, and restore_cleared_syserror. * tests/clock_nanosleep.c: New file. * tests/clock_nanosleep.test: New test. * tests/Makefile.am (check_PROGRAMS): Add clock_nanosleep. (TESTS): Add clock_nanosleep.test. * tests/.gitignore: Add clock_nanosleep. --- tests/.gitignore | 1 + tests/Makefile.am | 2 + tests/clock_nanosleep.c | 128 +++++++++++++++++++++++++++++++++++++ tests/clock_nanosleep.test | 14 ++++ time.c | 12 +++- 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 tests/clock_nanosleep.c create mode 100755 tests/clock_nanosleep.test diff --git a/tests/.gitignore b/tests/.gitignore index aca81289..485864d3 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -2,6 +2,7 @@ adjtimex aio bpf caps +clock_nanosleep clock_xettime epoll_create1 eventfd diff --git a/tests/Makefile.am b/tests/Makefile.am index dbe45112..d94eac6e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,7 @@ check_PROGRAMS = \ aio \ bpf \ caps \ + clock_nanosleep \ clock_xettime \ epoll_create1 \ eventfd \ @@ -105,6 +106,7 @@ TESTS = \ aio.test \ bpf.test \ caps.test \ + clock_nanosleep.test \ clock_xettime.test \ dumpio.test \ epoll_create1.test \ diff --git a/tests/clock_nanosleep.c b/tests/clock_nanosleep.c new file mode 100644 index 00000000..ff503c27 --- /dev/null +++ b/tests/clock_nanosleep.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +static void +handler(int signo) +{ +} + +int +main(void) +{ + struct { + struct timespec ts; + uint32_t pad[2]; + } req = { + .ts = { .tv_nsec = 0xc0de1 }, + .pad = { 0xdeadbeef, 0xbadc0ded } + }, rem = { + .ts = { .tv_sec = 0xc0de2, .tv_nsec = 0xc0de3 }, + .pad = { 0xdeadbeef, 0xbadc0ded } + }; + const sigset_t set = {}; + const struct sigaction act = { .sa_handler = handler }; + const struct itimerval itv = { + .it_interval.tv_usec = 222222, + .it_value.tv_usec = 111111 + }; + + if (syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &req.ts, NULL)) + return 77; + printf("clock_nanosleep(CLOCK_REALTIME, 0, {%jd, %jd}, NULL) = 0\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec); + + if (!syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, NULL, &rem.ts)) + return 77; + printf("clock_nanosleep(CLOCK_REALTIME, 0, NULL, %p)" + " = -1 EFAULT (Bad address)\n", &rem.ts); + + if (syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &req.ts, &rem.ts)) + return 77; + printf("clock_nanosleep(CLOCK_REALTIME, 0, {%jd, %jd}, %p) = 0\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec, &rem.ts); + + req.ts.tv_nsec = 999999999 + 1; + if (!syscall(__NR_clock_nanosleep, CLOCK_MONOTONIC, 0, &req.ts, &rem.ts)) + return 77; + printf("clock_nanosleep(CLOCK_MONOTONIC, 0" + ", {%jd, %jd}, %p) = -1 EINVAL (Invalid argument)\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec, &rem.ts); + + if (sigaction(SIGALRM, &act, NULL)) + return 77; + if (sigprocmask(SIG_SETMASK, &set, NULL)) + return 77; + + if (setitimer(ITIMER_REAL, &itv, NULL)) + return 77; + printf("setitimer(ITIMER_REAL, {it_interval={%jd, %jd}" + ", it_value={%jd, %jd}}, NULL) = 0\n", + (intmax_t) itv.it_interval.tv_sec, + (intmax_t) itv.it_interval.tv_usec, + (intmax_t) itv.it_value.tv_sec, + (intmax_t) itv.it_value.tv_usec); + + --req.ts.tv_nsec; + if (!syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &req.ts, &rem.ts)) + return 77; + printf("clock_nanosleep(CLOCK_REALTIME, 0, {%jd, %jd}, {%jd, %jd})" + " = ? ERESTART_RESTARTBLOCK (Interrupted by signal)\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec, + (intmax_t) rem.ts.tv_sec, (intmax_t) rem.ts.tv_nsec); + puts("--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---"); + + if (syscall(__NR_clock_gettime, CLOCK_REALTIME, &req.ts)) + return 77; + printf("clock_gettime(CLOCK_REALTIME, {%jd, %jd}) = 0\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec); + + ++req.ts.tv_sec; + rem.ts.tv_sec = 0xc0de4; + rem.ts.tv_nsec = 0xc0de5; + if (!syscall(__NR_clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, + &req.ts, &rem.ts)) + return 77; + printf("clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, {%jd, %jd}, %p)" + " = ? ERESTARTNOHAND (To be restarted if no handler)\n", + (intmax_t) req.ts.tv_sec, (intmax_t) req.ts.tv_nsec, &rem.ts); + puts("--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---"); + + puts("+++ exited with 0 +++"); + return 0; +} diff --git a/tests/clock_nanosleep.test b/tests/clock_nanosleep.test new file mode 100755 index 00000000..42453817 --- /dev/null +++ b/tests/clock_nanosleep.test @@ -0,0 +1,14 @@ +#!/bin/sh + +# Check clock_nanosleep syscall decoding. + +. "${srcdir=.}/init.sh" + +run_prog > /dev/null +OUT="$LOG.out" +syscalls=clock_nanosleep,clock_gettime,setitimer +run_strace -e trace=$syscalls $args > "$OUT" +match_diff "$OUT" "$LOG" +rm -f "$OUT" + +exit 0 diff --git a/time.c b/time.c index 47023c59..f93f1500 100644 --- a/time.c +++ b/time.c @@ -351,7 +351,17 @@ SYS_FUNC(clock_nanosleep) printtv(tcp, tcp->u_arg[2]); tprints(", "); } else { - printtv(tcp, tcp->u_arg[3]); + /* + * Second (returned) timespec is only significant + * if syscall was interrupted and flags is not TIMER_ABSTIME. + */ + if (!tcp->u_arg[1] && is_erestart(tcp)) { + temporarily_clear_syserror(tcp); + printtv(tcp, tcp->u_arg[3]); + restore_cleared_syserror(tcp); + } else { + printaddr(tcp->u_arg[3]); + } } return 0; } -- 2.40.0