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.
diff --git a/NEWS b/NEWS
index 24365b0..c5a4d2e 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@
* 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 cda5f92..d8444f3 100644
--- a/io.c
+++ b/io.c
@@ -221,7 +221,8 @@
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 53d7ed6..0fabed2 100644
--- a/tests/preadv.c
+++ b/tests/preadv.c
@@ -92,6 +92,61 @@
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;
}