]> granicus.if.org Git - strace/commitdiff
tests: check syscall fault injection
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 16 Nov 2016 17:27:46 +0000 (17:27 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 16 Nov 2016 17:27:46 +0000 (17:27 +0000)
* tests/fault_injection.c: New file.
* tests/fault_injection.test: New test.
* tests/fault_syntax.test: Likewise.
* tests/.gitignore: Add fault_injection.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(MISC_TESTS): Add fault_injection.test and fault_syntax.test.

tests/.gitignore
tests/Makefile.am
tests/fault_injection.c [new file with mode: 0644]
tests/fault_injection.test [new file with mode: 0755]
tests/fault_syntax.test [new file with mode: 0755]

index 0366c9c45ac3b643d6479374884263231086f3d2..6fc3cd1f31a58b87ccef368d2178b7c6a62390fa 100644 (file)
@@ -52,6 +52,7 @@ fadvise64_64
 fallocate
 fanotify_init
 fanotify_mark
+fault_injection
 fchdir
 fchmod
 fchmodat
index 0f04779354b2defc2f17b78512ea818d2a3142f0..df5ddb21b5ddee1e0b5069babbca77be8ae9af38 100644 (file)
@@ -112,6 +112,7 @@ check_PROGRAMS = \
        fallocate \
        fanotify_init \
        fanotify_mark \
+       fault_injection \
        fchdir \
        fchmod \
        fchmodat \
@@ -785,6 +786,8 @@ MISC_TESTS = \
        detach-running.test \
        detach-sleeping.test \
        detach-stopped.test \
+       fault_injection.test \
+       fault_syntax.test \
        filter-unavailable.test \
        fork-f.test \
        ksysent.test \
diff --git a/tests/fault_injection.c b/tests/fault_injection.c
new file mode 100644 (file)
index 0000000..3305d0f
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Check that fault injection works properly.
+ *
+ * Copyright (c) 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"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+static const int expfd = 4;
+static const int gotfd = 5;
+
+#ifndef __s390__
+# define DEFAULT_ERRNO ENOSYS
+#else /* __s390__ */
+/* Invalid syscall number causes EPERM instead of traditional ENOSYS. */
+# define DEFAULT_ERRNO EPERM
+#endif
+
+static const char *errstr;
+static int is_raw, err, first, step, iter, try;
+
+static void
+invoke(int fail)
+{
+       static char buf[sizeof(int) * 3 + 3];
+       const struct iovec io = {
+               .iov_base = buf,
+               .iov_len = sprintf(buf, "%d.", ++try)
+       };
+       int rc;
+
+       if (!fail) {
+               rc = write(expfd, io.iov_base, io.iov_len);
+               if (rc != (int) io.iov_len)
+                       perror_msg_and_fail("write");
+       }
+
+       errno = 0;
+       rc = writev(gotfd, &io, 1);
+
+       if (fail) {
+               if (!(rc == -1 && errno == err))
+                       perror_msg_and_fail("expected errno %d"
+                                           ", got rc == %d, errno == %d",
+                                           err, rc, errno);
+
+               if (is_raw)
+                       tprintf("writev(%#x, %p, 0x1) = -1 (errno %d)"
+                               " (INJECTED)\n", gotfd, &io, err);
+               else
+                       tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
+                               " = -1 %s (%m) (INJECTED)\n",
+                               gotfd, buf, (int) io.iov_len, errstr);
+       } else {
+               if (rc != (int) io.iov_len)
+                       perror_msg_and_fail("expected %d"
+                                           ", got rc == %d, errno == %d",
+                                           (int) io.iov_len, rc, errno);
+
+               if (is_raw)
+                       tprintf("writev(%#x, %p, 0x1) = %#x\n", gotfd, &io, rc);
+               else
+                       tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
+                               " = %d\n",
+                               gotfd, buf, (int) io.iov_len, (int) io.iov_len);
+       }
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct stat st;
+
+       assert(fstat(expfd, &st) == 0);
+       assert(fstat(gotfd, &st) == 0);
+
+       assert(argc == 6);
+
+       is_raw = !strcmp("raw", argv[1]);
+
+       errstr = argv[2];
+       err = atoi(errstr);
+       assert(err >= 0);
+
+       if (!err) {
+               if (!*errstr)
+                       err = DEFAULT_ERRNO;
+               else if (!strcmp(errstr, "EINVAL"))
+                       err = EINVAL;
+               else
+                       err = ENOSYS;
+       }
+
+       errno = err;
+       errstr = errno2name();
+
+       first = atoi(argv[3]);
+       step = atoi(argv[4]);
+       iter = atoi(argv[5]);
+
+       assert(first > 0);
+       assert(step >= 0);
+
+       tprintf("%s", "");
+
+       int i;
+       for (i = 1; i <= iter; ++i) {
+               int fail = 0;
+               if (first > 0) {
+                       --first;
+                       if (first == 0) {
+                               fail = 1;
+                               first = step;
+                       }
+               }
+               invoke(fail);
+       }
+
+       tprintf("%s\n", "+++ exited with 0 +++");
+       return 0;
+}
diff --git a/tests/fault_injection.test b/tests/fault_injection.test
new file mode 100755 (executable)
index 0000000..bf6006f
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# Check that fault injection works properly.
+#
+# Copyright (c) 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.
+
+. "${srcdir=.}/init.sh"
+
+#
+# F
+# F+
+# F+S
+
+N=16
+
+check_fault_injection()
+{
+       local trace fault err first step
+       trace=$1; shift
+       fault=$1; shift
+       err=$1; shift
+       first=$1; shift
+       step=$1; shift
+
+       local when=
+       if [ -z "$first$step" ]; then
+               first=1
+               step=1
+       else
+               case "$step" in
+                       '') when=":when=$first"; step=0 ;;
+                       +) when=":when=$first+"; step=1 ;;
+                       *) when=":when=$first+$step" ;;
+               esac
+       fi
+
+       local error=
+       local raw=reg
+       set --
+       case "$err" in
+               '') ;;
+               [123456789]*)
+                       error=":error=$err"
+                       raw=raw
+                       set -- -e raw=all
+                       ;;
+               *) error=":error=$err" ;;
+       esac
+
+       outexp="$NAME.out.exp"
+       outgot="$NAME.out.got"
+
+       run_strace -a11 -e trace=$trace \
+               -e fault=$fault$when$error "$@" \
+               ./$NAME $raw "$err" "$first" "$step" $N \
+               > "$EXP" 4> "$outexp" 5> "$outgot"
+
+       match_diff "$EXP" "$LOG"
+       match_diff "$outexp" "$outgot"
+       rm -f "$EXP" "$outexp" "$outgot"
+}
+
+for err in '' ENOSYS 22 EINVAL; do
+       for fault in writev 51,desc; do
+               check_fault_injection \
+                       writev $fault "$err" '' ''
+               for F in 1 2 3 5 7 11; do
+                       check_fault_injection \
+                               writev $fault "$err" $F ''
+                       check_fault_injection \
+                               writev $fault "$err" $F +
+                       for S in 1 2 3 5 7 11; do
+                               check_fault_injection \
+                                       writev $fault "$err" $F $S
+                       done
+               done
+       done
+done
diff --git a/tests/fault_syntax.test b/tests/fault_syntax.test
new file mode 100755 (executable)
index 0000000..97766d2
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# Check -e fault= syntax.
+#
+# Copyright (c) 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.
+
+. "${srcdir=.}/init.sh"
+
+#
+# F
+# F+
+# F+S
+
+fail_with()
+{
+       dump_log_and_fail_with \
+               "strace -e fault=$* failed to handle an argument error properly"
+}
+
+for arg in invalid_syscall_name \
+          invalid_syscall_name:when=3 \
+          -1 \
+          -1:when=4 \
+          -2 \
+          -2:when=5 \
+          32767 \
+          32767:when=6 \
+          chdir:42 \
+          chdir:42:when=7 \
+          chdir:invalid \
+          chdir:invalid:when=8 \
+          chdir:error= \
+          chdir:error=:when=10 \
+          chdir:error=invalid_error_name \
+          chdir:error=invalid_error_name:when=11 \
+          chdir:error=-1 \
+          chdir:error=-1:when=12 \
+          chdir:error=-2 \
+          chdir:error=-2:when=13 \
+          chdir:error=3+ \
+          chdir:error=3+:when=14 \
+          chdir:error=4096 \
+          chdir:error=4096:when=15 \
+          chdir:when=7:error=invalid_error_name \
+          chdir:when= \
+          chdir:when=:error=19 \
+          chdir:when=0 \
+          chdir:when=0:error=20 \
+          chdir:when=-1 \
+          chdir:when=-1:error=21 \
+          chdir:when=-2+ \
+          chdir:when=-2+:error=22 \
+          chdir:when=-3+0 \
+          chdir:when=-3+0:error=23 \
+          chdir:when=4- \
+          chdir:when=4-:error=24 \
+          chdir:when=5+- \
+          chdir:when=5+-:error=25 \
+          chdir:when=6++ \
+          chdir:when=6++:error=26 \
+          chdir:when=7+0 \
+          chdir:when=7+0:error=27 \
+          chdir:when=8+-1 \
+          chdir:when=8+-1:error=28 \
+          chdir:when=9+1+ \
+          chdir:when=9+1+:error=29 \
+          chdir:when=65536 \
+          chdir:when=65536:error=30 \
+          chdir:when=1+65536 \
+          chdir:when=1+65536:error=31 \
+          ; do
+       $STRACE -e fault="$arg" true 2> "$LOG" &&
+               fail_with "$arg"
+       LC_ALL=C grep -F 'invalid fault argument' < "$LOG" > /dev/null ||
+               fail_with "$arg"
+done
+
+exit 0