From c98ab8805b3876426c8d4359fa1c981c324923bf Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 30 Mar 2016 18:04:00 +0000 Subject: [PATCH] Fix decoding of preadv syscall in case of short read * io.c (SYS_FUNC(preadv)): Call tprint_iov_upto instead of tprint_iov and specify syscall return value as a data size limit. * NEWS: Mention it. * tests/preadv.c (main): Add a test case for preadv short read. --- NEWS | 1 + io.c | 3 ++- tests/preadv.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 24365b05..c5a4d2e0 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,7 @@ Noteworthy changes in release ?.?? (????-??-??) * Fixed decoding of mlock2 syscall on sparc. * Fixed decoding of syscalls unknown to the kernel on s390/s390x. (addresses Debian bug #485979 and Fedora bug #1298294). + * Fixed decoding of preadv syscall in case of short read. * Fixed decoding and dumping of readv syscall in case of short read. * Fixed dumping of recvmsg and recvmmsg syscalls in case of short read. * Fixed decoding of mincore syscall's last argument. diff --git a/io.c b/io.c index cda5f92c..d8444f39 100644 --- a/io.c +++ b/io.c @@ -221,7 +221,8 @@ SYS_FUNC(preadv) printfd(tcp, tcp->u_arg[0]); tprints(", "); } else { - tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1); + tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1, + tcp->u_rval); tprintf(", %lu, ", tcp->u_arg[2]); print_lld_from_low_high_val(tcp, 3); } diff --git a/tests/preadv.c b/tests/preadv.c index 53d7ed67..0fabed25 100644 --- a/tests/preadv.c +++ b/tests/preadv.c @@ -92,6 +92,61 @@ main(void) perror_msg_and_fail("preadv"); printf("preadv(0, [], 0, -3) = -1 EINVAL (%m)\n"); + static const char tmp[] = "preadv-tmpfile"; + int fd = open(tmp, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + perror_msg_and_fail("open"); + if (unlink(tmp)) + perror_msg_and_fail("unlink"); + + static const char w[] = "0123456789abcde"; + if (write(fd, w, LENGTH_OF(w)) != LENGTH_OF(w)) + perror_msg_and_fail("write"); + + static const char r0_c[] = "01234567"; + static const char r1_c[] = "89abcde"; + + const unsigned int r_len = (LENGTH_OF(w) + 1) / 2; + void *r0 = tail_alloc(r_len); + const struct iovec r0_iov_[] = { + { + .iov_base = r0, + .iov_len = r_len + } + }; + const struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_)); + + long rc; + + rc = preadv(fd, r_iov, ARRAY_SIZE(r0_iov_), 0); + if (rc != (int) r_len) + perror_msg_and_fail("preadv: expected %u, returned %ld", + r_len, rc); + printf("preadv(%d, [{\"%s\", %u}], %u, 0) = %u\n", + fd, r0_c, r_len, ARRAY_SIZE(r0_iov_), r_len); + + void *r1 = tail_alloc(r_len); + void *r2 = tail_alloc(LENGTH_OF(w)); + const struct iovec r1_iov_[] = { + { + .iov_base = r1, + .iov_len = r_len + }, + { + .iov_base = r2, + .iov_len = LENGTH_OF(w) + } + }; + r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_)); + + rc = preadv(fd, r_iov, ARRAY_SIZE(r1_iov_), r_len); + if (rc != (int) LENGTH_OF(w) - r_len) + perror_msg_and_fail("preadv: expected %d, returned %ld", + (int) LENGTH_OF(w) - r_len, rc); + printf("preadv(%d, [{\"%s\", %u}, {\"\", %u}], %u, %u) = %u\n", + fd, r1_c, r_len, LENGTH_OF(w), ARRAY_SIZE(r1_iov_), + r_len, LENGTH_OF(w) - r_len); + puts("+++ exited with 0 +++"); return 0; } -- 2.40.0