From: Dmitry V. Levin Date: Wed, 30 Mar 2016 03:54:21 +0000 (+0000) Subject: Fix printing of negative offsets in preadv and pwritev syscalls X-Git-Tag: v4.12~472 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d461151f2384834d9c6cc98dc7285f363a6186ed;p=strace Fix printing of negative offsets in preadv and pwritev syscalls * io.c (print_llu_from_low_high_val): Rename to print_lld_from_low_high_val, all callers changed. Print value as a signed integer. * tests/preadv.c: New file. * tests/preadv.test: New test. * tests/pwritev.c: New file. * tests/pwritev.test: New test. * tests/.gitignore: Add preadv and pwritev. * tests/Makefile.am (check_PROGRAMS): Likewise. (preadv_CPPFLAGS, pwritev_CPPFLAGS): New variables. (DECODER_TESTS): Add preadv.test and pwritev.test. --- diff --git a/io.c b/io.c index aac93eae..cda5f92c 100644 --- a/io.c +++ b/io.c @@ -186,7 +186,7 @@ SYS_FUNC(pwrite) } static void -print_llu_from_low_high_val(struct tcb *tcp, int arg) +print_lld_from_low_high_val(struct tcb *tcp, int arg) { #if SIZEOF_LONG == SIZEOF_LONG_LONG # if SUPPORTED_PERSONALITIES > 1 @@ -196,20 +196,20 @@ print_llu_from_low_high_val(struct tcb *tcp, int arg) if (current_wordsize == sizeof(long)) # endif # endif - tprintf("%lu", (unsigned long) tcp->u_arg[arg]); + tprintf("%ld", tcp->u_arg[arg]); # if SUPPORTED_PERSONALITIES > 1 else - tprintf("%lu", + tprintf("%ld", ((unsigned long) tcp->u_arg[arg + 1] << current_wordsize * 8) | (unsigned long) tcp->u_arg[arg]); # endif #else # ifdef X32 if (current_personality == 0) - tprintf("%llu", (unsigned long long) tcp->ext_arg[arg]); + tprintf("%lld", tcp->ext_arg[arg]); else # endif - tprintf("%llu", + tprintf("%lld", ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8) | (unsigned long long) (unsigned long) tcp->u_arg[arg]); #endif @@ -223,7 +223,7 @@ SYS_FUNC(preadv) } else { tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); tprintf(", %lu, ", tcp->u_arg[2]); - print_llu_from_low_high_val(tcp, 3); + print_lld_from_low_high_val(tcp, 3); } return 0; } @@ -234,7 +234,7 @@ SYS_FUNC(pwritev) tprints(", "); tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); tprintf(", %lu, ", tcp->u_arg[2]); - print_llu_from_low_high_val(tcp, 3); + print_lld_from_low_high_val(tcp, 3); return RVAL_DECODED; } diff --git a/tests/.gitignore b/tests/.gitignore index d5bbe588..1e1da482 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -89,7 +89,9 @@ personality pipe poll ppoll +preadv pselect6 +pwritev readdir readlink readlinkat diff --git a/tests/Makefile.am b/tests/Makefile.am index 88324937..7e4038c7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -138,7 +138,9 @@ check_PROGRAMS = \ pipe \ poll \ ppoll \ + preadv \ pselect6 \ + pwritev \ readdir \ readlink \ readlinkat \ @@ -222,11 +224,14 @@ mmap64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 mq_LDADD = -lrt $(LDADD) newfstatat_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 pc_LDADD = $(dl_LIBS) $(LDADD) +preadv_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 +pwritev_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 stat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 statfs_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 times_LDADD = -lrt $(LDADD) truncate64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 uio_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64 + stack_fcall_SOURCES = stack-fcall.c \ stack-fcall-0.c stack-fcall-1.c stack-fcall-2.c stack-fcall-3.c @@ -309,7 +314,9 @@ DECODER_TESTS = \ pipe.test \ poll.test \ ppoll.test \ + preadv.test \ pselect6.test \ + pwritev.test \ readdir.test \ readlink.test \ readlinkat.test \ diff --git a/tests/preadv.c b/tests/preadv.c new file mode 100644 index 00000000..53d7ed67 --- /dev/null +++ b/tests/preadv.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014-2016 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. + */ + +#include "tests.h" + +#ifdef HAVE_PREADV + +# include +# include +# include +# include + +# define LEN 8 + +static void +print_iov(const struct iovec *iov) +{ + unsigned int i; + unsigned char *buf = iov->iov_base; + + fputs("{\"", stdout); + for (i = 0; i < iov->iov_len; ++i) + printf("\\%d", (int) buf[i]); + printf("\", %u}", (unsigned) iov->iov_len); +} + +static void +print_iovec(const struct iovec *iov, unsigned int cnt) +{ + unsigned int i; + putchar('['); + for (i = 0; i < cnt; ++i) { + if (i) + fputs(", ", stdout); + print_iov(&iov[i]); + } + putchar(']'); +} + +int +main(void) +{ + const off_t offset = 0xdefaceddeadbeefLL; + char *buf = tail_alloc(LEN); + struct iovec *iov = tail_alloc(sizeof(*iov)); + iov->iov_base = buf; + iov->iov_len = LEN; + + (void) close(0); + if (open("/dev/zero", O_RDONLY)) + perror_msg_and_fail("open"); + + if (preadv(0, iov, 1, offset) != LEN) + perror_msg_and_fail("preadv"); + printf("preadv(0, "); + print_iovec(iov, 1); + printf(", 1, %lld) = %u\n", (long long) offset, LEN); + + if (preadv(0, iov, 1, -1) != -1) + perror_msg_and_fail("preadv"); + printf("preadv(0, %p, 1, -1) = -1 EINVAL (%m)\n", iov); + + if (preadv(0, NULL, 1, -2) != -1) + perror_msg_and_fail("preadv"); + printf("preadv(0, NULL, 1, -2) = -1 EINVAL (%m)\n"); + + if (preadv(0, NULL, 0, -3) != -1) + perror_msg_and_fail("preadv"); + printf("preadv(0, [], 0, -3) = -1 EINVAL (%m)\n"); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("HAVE_PREADV") + +#endif diff --git a/tests/preadv.test b/tests/preadv.test new file mode 100755 index 00000000..d1abdb7d --- /dev/null +++ b/tests/preadv.test @@ -0,0 +1,6 @@ +#!/bin/sh + +# Check preadv syscall decoding. + +. "${srcdir=.}/init.sh" +run_strace_match_diff -a21 diff --git a/tests/pwritev.c b/tests/pwritev.c new file mode 100644 index 00000000..99b30183 --- /dev/null +++ b/tests/pwritev.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014-2016 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. + */ + +#include "tests.h" + +#ifdef HAVE_PWRITEV + +# include +# include +# include +# include + +# define LEN 8 +# define LIM (LEN - 1) + +static void +print_iov(const struct iovec *iov) +{ + unsigned int i; + unsigned char *buf = iov->iov_base; + + fputs("{\"", stdout); + for (i = 0; i < iov->iov_len; ++i) { + if (i < LIM) + printf("\\%d", (int) buf[i]); + } + printf("\"%s, %u}", + i > LIM ? "..." : "", (unsigned) iov->iov_len); +} + +static void +print_iovec(const struct iovec *iov, unsigned int cnt, unsigned int size) +{ + if (!size) { + printf("%p", iov); + return; + } + unsigned int i; + putchar('['); + for (i = 0; i < cnt; ++i) { + if (i) + fputs(", ", stdout); + if (i == LIM) { + fputs("...", stdout); + break; + } + if (i == size) { + printf("%p", &iov[i]); + break; + } + print_iov(&iov[i]); + } + putchar(']'); +} + +int +main(void) +{ + (void) close(0); + if (open("/dev/null", O_WRONLY)) + perror_msg_and_fail("open"); + + char *buf = tail_alloc(LEN); + unsigned i; + for (i = 0; i < LEN; ++i) + buf[i] = i; + + struct iovec *iov = tail_alloc(sizeof(*iov) * LEN); + for (i = 0; i < LEN; ++i) { + buf[i] = i; + iov[i].iov_base = &buf[i]; + iov[i].iov_len = LEN - i; + } + tail_alloc(1); + + const off_t offset = 0xdefaceddeadbeefLL; + int written = 0; + for (i = 0; i < LEN; ++i) { + written += iov[i].iov_len; + if (pwritev(0, iov, i + 1, offset + i) != written) + perror_msg_and_fail("pwritev"); + fputs("pwritev(0, ", stdout); + print_iovec(iov, i + 1, LEN); + printf(", %u, %lld) = %d\n", + i + 1, (long long) offset + i, written); + } + + for (i = 0; i <= LEN; ++i) { + unsigned int n = LEN + 1 - i; + if (pwritev(0, iov + i, n, offset + LEN + i) != -1) + perror_msg_and_fail("pwritev"); + fputs("pwritev(0, ", stdout); + print_iovec(iov + i, n, LEN - i); + printf(", %u, %lld) = -1 EFAULT (%m)\n", + n, (long long) offset + LEN + i); + } + + iov->iov_base = iov + LEN * 2; + if (pwritev(0, iov, 1, -1) != -1) + perror_msg_and_fail("pwritev"); + printf("pwritev(0, [{%p, %d}], 1, -1) = -1 EINVAL (%m)\n", + iov->iov_base, LEN); + + iov += LEN; + if (pwritev(0, iov, 42, -2) != -1) + perror_msg_and_fail("pwritev"); + printf("pwritev(0, %p, 42, -2) = -1 EINVAL (%m)\n", iov); + + if (pwritev(0, NULL, 1, -3) != -1) + perror_msg_and_fail("pwritev"); + printf("pwritev(0, NULL, 1, -3) = -1 EINVAL (%m)\n"); + + if (pwritev(0, NULL, 0, -4) != -1) + perror_msg_and_fail("pwritev"); + printf("pwritev(0, [], 0, -4) = -1 EINVAL (%m)\n"); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("HAVE_PWRITEV") + +#endif diff --git a/tests/pwritev.test b/tests/pwritev.test new file mode 100755 index 00000000..0aed6835 --- /dev/null +++ b/tests/pwritev.test @@ -0,0 +1,6 @@ +#!/bin/sh + +# Check pwritev syscall decoding. + +. "${srcdir=.}/init.sh" +run_strace_match_diff -a22 -s7