From: Dmitry V. Levin Date: Sun, 3 Apr 2016 16:37:43 +0000 (+0000) Subject: tests: add read-write.test X-Git-Tag: v4.12~453 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2aa9b32d81656c3f22fa9efb198985a37ea63754;p=strace tests: add read-write.test * tests/read-write.c: New file. * tests/read-write.test: New test. * tests/.gitignore: Add read-write. * tests/Makefile.am (check_PROGRAMS): Likewise. (DECODER_TESTS): Add read-write.test. --- diff --git a/tests/.gitignore b/tests/.gitignore index 3d6d93e9..c240a112 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -99,6 +99,7 @@ preadv preadv-pwritev pselect6 pwritev +read-write readdir readlink readlinkat diff --git a/tests/Makefile.am b/tests/Makefile.am index 12afd496..0f4a329f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -148,6 +148,7 @@ check_PROGRAMS = \ preadv-pwritev \ pselect6 \ pwritev \ + read-write \ readdir \ readlink \ readlinkat \ @@ -334,6 +335,7 @@ DECODER_TESTS = \ preadv-pwritev.test \ pselect6.test \ pwritev.test \ + read-write.test \ readdir.test \ readlink.test \ readlinkat.test \ diff --git a/tests/read-write.c b/tests/read-write.c new file mode 100644 index 00000000..4efe1473 --- /dev/null +++ b/tests/read-write.c @@ -0,0 +1,210 @@ +/* + * Check decoding and dumping of read and write syscalls. + * + * Copyright (c) 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" + +#include +#include +#include +#include + +static void +dump_str(const char *str, const unsigned int len) +{ + static const char dots[16] = "................"; + unsigned int i; + + for (i = 0; i < len; i += 16) { + unsigned int n = len - i > 16 ? 16 : len - i; + const char *dump = hexdump_memdup(str + i, n); + + tprintf(" | %05x %-49s %-16.*s |\n", + i, dump, n, dots); + + free((void *) dump); + } +} + +static void +print_hex(const char *str, const unsigned int len) +{ + const unsigned char *ustr = (const unsigned char *) str; + unsigned int i; + + for (i = 0; i < len; ++i) { + unsigned int c = ustr[i]; + + switch (c) { + case '\t': + tprintf("\\t"); break; + case '\n': + tprintf("\\n"); break; + case '\v': + tprintf("\\v"); break; + case '\f': + tprintf("\\f"); break; + case '\r': + tprintf("\\r"); break; + default: + tprintf("\\%o", ustr[i]); + } + } +} + +static void +test_dump(const unsigned int len) +{ + static char *buf; + + if (buf) { + size_t ps1 = get_page_size() - 1; + buf = (void *) (((size_t) buf + ps1) & ~ps1) - len; + } else { + buf = tail_alloc(len); + } + + long rc = read(0, buf, len); + if (rc != (int) len) + perror_msg_and_fail("read: expected %d, returned %ld", + len, rc); + + tprintf("%s(%d, \"", "read", 0); + print_hex(buf, len); + tprintf("\", %d) = %ld\n", len, rc); + dump_str(buf, len); + + unsigned int i; + for (i = 0; i < len; ++i) + buf[i] = i; + + rc = write(1, buf, len); + if (rc != (int) len) + perror_msg_and_fail("write: expected %d, returned %ld", + len, rc); + + tprintf("%s(%d, \"", "write", 1); + print_hex(buf, len); + tprintf("\", %d) = %ld\n", len, rc); + dump_str(buf, len); + + if (!len) + buf = 0; +} + +int +main(void) +{ + tprintf("%s", ""); + + static char tmp[] = "read-write-tmpfile"; + if (open(tmp, O_CREAT|O_RDONLY|O_TRUNC, 0600) != 0) + perror_msg_and_fail("creat: %s", tmp); + if (open(tmp, O_WRONLY) != 1) + perror_msg_and_fail("open: %s", tmp); + + static const char w_c[] = "0123456789abcde"; + const unsigned int w_len = LENGTH_OF(w_c); + const char *w_d = hexdump_strdup(w_c); + const void *w = tail_memdup(w_c, w_len); + + static const char r0_c[] = "01234567"; + const char *r0_d = hexdump_strdup(r0_c); + const unsigned int r0_len = (w_len + 1) / 2; + void *r0 = tail_alloc(r0_len); + + static const char r1_c[] = "89abcde"; + const char *r1_d = hexdump_strdup(r1_c); + const unsigned int r1_len = w_len - r0_len; + void *r1 = tail_alloc(w_len); + + void *efault = r1 - get_page_size(); + + long rc; + + rc = write(1, w, 0); + if (rc) + perror_msg_and_fail("write: expected 0, returned %ld", rc); + tprintf("write(1, \"\", 0) = 0\n"); + + rc = write(1, w, w_len + 1); + if (rc != -1) + perror_msg_and_fail("write: expected -1 EFAULT" + ", returned %ld", rc); + tprintf("write(1, %p, %u) = -1 EFAULT (%m)\n", + w, w_len + 1); + + rc = write(1, w, w_len); + if (rc != (int) w_len) + perror_msg_and_fail("write: expected %u, returned %ld", + w_len, rc); + tprintf("write(1, \"%s\", %u) = %ld\n" + " | 00000 %-49s %-16s |\n", + w_c, w_len, rc, w_d, w_c); + close(1); + + rc = read(0, r0, 0); + if (rc) + perror_msg_and_fail("read: expected 0, returned %ld", rc); + tprintf("read(0, \"\", 0) = 0\n"); + + rc = read(0, efault, 1); + if (rc != -1) + perror_msg_and_fail("read: expected -1, returned %ld", rc); + tprintf("read(0, %p, 1) = -1 EFAULT (%m)\n", efault); + + rc = read(0, r0, r0_len); + if (rc != (int) r0_len) + perror_msg_and_fail("read: expected %u, returned %ld", + r0_len, rc); + tprintf("read(0, \"%s\", %u) = %ld\n" + " | 00000 %-49s %-16s |\n", + r0_c, r0_len, rc, r0_d, r0_c); + + rc = read(0, r1, w_len); + if (rc != (int) r1_len) + perror_msg_and_fail("read: expected %u, returned %ld", + r1_len, rc); + tprintf("read(0, \"%s\", %u) = %ld\n" + " | 00000 %-49s %-16s |\n", + r1_c, w_len, rc, r1_d, r1_c); + close(0); + + if (open("/dev/zero", O_RDONLY)) + perror_msg_and_fail("open"); + + if (open("/dev/null", O_WRONLY) != 1) + perror_msg_and_fail("open"); + + unsigned int i; + for (i = 0; i <= 32; ++i) + test_dump(i); + + tprintf("+++ exited with 0 +++\n"); + return 0; +} diff --git a/tests/read-write.test b/tests/read-write.test new file mode 100755 index 00000000..3700541f --- /dev/null +++ b/tests/read-write.test @@ -0,0 +1,18 @@ +#!/bin/sh + +# Check decoding and dumping of read and write syscalls. + +. "${srcdir=.}/init.sh" + +# strace -P is implemented using /proc/self/fd +[ -d /proc/self/fd/ ] || + framework_skip_ '/proc/self/fd/ is not available' + +tmpfile=read-write-tmpfile +> $tmpfile + +run_strace_match_diff \ + -a15 -eread=0 -ewrite=1 -e trace=read,write \ + -P $tmpfile -P /dev/zero -P /dev/null + +rm -f $tmpfile