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.
This commit is contained in:
Дмитрий Левин 2016-03-30 03:54:21 +00:00
parent 0a9d1947a7
commit d461151f23
7 changed files with 280 additions and 7 deletions

14
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;
}

2
tests/.gitignore vendored

@ -89,7 +89,9 @@ personality
pipe
poll
ppoll
preadv
pselect6
pwritev
readdir
readlink
readlinkat

@ -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 \

103
tests/preadv.c Normal file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
* 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 <fcntl.h>
# include <stdio.h>
# include <sys/uio.h>
# include <unistd.h>
# 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

6
tests/preadv.test Executable file

@ -0,0 +1,6 @@
#!/bin/sh
# Check preadv syscall decoding.
. "${srcdir=.}/init.sh"
run_strace_match_diff -a21

149
tests/pwritev.c Normal file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
* 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 <fcntl.h>
# include <stdio.h>
# include <sys/uio.h>
# include <unistd.h>
# 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

6
tests/pwritev.test Executable file

@ -0,0 +1,6 @@
#!/bin/sh
# Check pwritev syscall decoding.
. "${srcdir=.}/init.sh"
run_strace_match_diff -a22 -s7