tests: check decoding of mq_{notify,open,timedreceive,timedsend,unlink}
authorEugene Syromyatnikov <evgsyr@gmail.com>
Thu, 27 Oct 2016 07:18:44 +0000 (10:18 +0300)
committerEugene Syromyatnikov <evgsyr@gmail.com>
Wed, 9 Nov 2016 01:27:53 +0000 (04:27 +0300)
* tests/mq_sendrecv.c: New file.
* tests/mq_sendrecv-read.c: Likewise.
* tests/mq_sendrecv-write.c: Likewise.
* tests/mq_sendrecv.test: New test.
* tests/mq_sendrecv-read.test: Likewise.
* tests/mq_sendrecv-write.test: Likewise.
* tests/.gitignore: Add mq_sendrecv, mq_sendrecv-read,
and mq_sendrecv-write.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(mq_sendrecv_LDADD, mq_sendrecv_read_LDADD, mq_sendrecv_write_LDADD):
New variables.
(DECODER_TESTS): Add mq_sendrecv.test, mq_sendrecv-read.test,
and mq_sendrecv-write.test.

tests/.gitignore
tests/Makefile.am
tests/mq_sendrecv-read.c [new file with mode: 0644]
tests/mq_sendrecv-read.test [new file with mode: 0755]
tests/mq_sendrecv-write.c [new file with mode: 0644]
tests/mq_sendrecv-write.test [new file with mode: 0755]
tests/mq_sendrecv.c [new file with mode: 0644]
tests/mq_sendrecv.test [new file with mode: 0755]

index c0ebebbfd616410512231e40e6f2a18f314be075..05f1512f8b900097468eaff266c11c353f4a8173 100644 (file)
@@ -164,6 +164,9 @@ mmsg_name-v
 mount
 move_pages
 mq
+mq_sendrecv
+mq_sendrecv-read
+mq_sendrecv-write
 msg_control
 msg_control-v
 msg_name
index 0623e006938d058c5dc3ff3e89d06960bdac5b4e..e1da8a5458e9e34a9a9e7693796d4fb61471943b 100644 (file)
@@ -222,6 +222,9 @@ check_PROGRAMS = \
        mount \
        move_pages \
        mq \
+       mq_sendrecv \
+       mq_sendrecv-read \
+       mq_sendrecv-write \
        msg_control \
        msg_control-v \
        msg_name \
@@ -412,6 +415,9 @@ ftruncate64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 lstat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 mmap64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 mq_LDADD = -lrt $(LDADD)
+mq_sendrecv_LDADD = -lrt $(LDADD)
+mq_sendrecv_read_LDADD = -lrt $(LDADD)
+mq_sendrecv_write_LDADD = -lrt $(LDADD)
 newfstatat_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 pc_LDADD = $(dl_LIBS) $(LDADD)
 pread64_pwrite64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
@@ -587,6 +593,9 @@ DECODER_TESTS = \
        mount.test \
        move_pages.test \
        mq.test \
+       mq_sendrecv.test \
+       mq_sendrecv-read.test \
+       mq_sendrecv-write.test \
        msg_control.test \
        msg_control-v.test \
        msg_name.test \
diff --git a/tests/mq_sendrecv-read.c b/tests/mq_sendrecv-read.c
new file mode 100644 (file)
index 0000000..cc9867b
--- /dev/null
@@ -0,0 +1,3 @@
+#define DUMPIO_READ 1
+#define MQ_NAME "mq_sendrecv-read.sample"
+#include "mq_sendrecv.c"
diff --git a/tests/mq_sendrecv-read.test b/tests/mq_sendrecv-read.test
new file mode 100755 (executable)
index 0000000..eb4ad75
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check decoding of mq_open, mq_notify, mq_timedsend, mq_timedreceive syscalls.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -e trace=mq_open,mq_notify,mq_timedsend,mq_timedreceive,mq_unlink -eread=0 -a14
diff --git a/tests/mq_sendrecv-write.c b/tests/mq_sendrecv-write.c
new file mode 100644 (file)
index 0000000..ae34ee1
--- /dev/null
@@ -0,0 +1,3 @@
+#define DUMPIO_WRITE 1
+#define MQ_NAME "mq_sendrecv-write.sample"
+#include "mq_sendrecv.c"
diff --git a/tests/mq_sendrecv-write.test b/tests/mq_sendrecv-write.test
new file mode 100755 (executable)
index 0000000..38277ec
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check decoding of mq_open, mq_notify, mq_timedsend, mq_timedreceive syscalls.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -e trace=mq_open,mq_notify,mq_timedsend,mq_timedreceive,mq_unlink -ewrite=0 -a14
diff --git a/tests/mq_sendrecv.c b/tests/mq_sendrecv.c
new file mode 100644 (file)
index 0000000..de6464b
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Check decoding of mq_open, mq_timedsend, mq_notify, mq_timedreceive and
+ * mq_unlink syscalls.
+ *
+ * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * 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 <asm/unistd.h>
+
+#if defined __NR_mq_open && __NR_mq_timedsend && __NR_mq_timedreceive && \
+       __NR_mq_notify && __NR_mq_unlink
+
+# include <assert.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <inttypes.h>
+# include <signal.h>
+# include <stdbool.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <time.h>
+# include <unistd.h>
+
+# include "kernel_types.h"
+# include "sigevent.h"
+
+# ifndef MQ_NAME
+#  define MQ_NAME "mq_sendrecv.sample"
+# endif
+
+# ifndef DUMPIO_READ
+#  define DUMPIO_READ 0
+# endif
+
+# ifndef DUMPIO_WRITE
+#  define DUMPIO_WRITE 0
+# endif
+
+
+enum {
+       NUM_ATTRS = 8,
+       MSG_CUT = 8,
+       MSG_MAX_UNCUT = 32,
+       MSG_SIZE = 64,
+       MSG_START = 0x80,
+};
+
+
+static void
+printstr(unsigned char start, unsigned int count)
+{
+       unsigned int i;
+
+       printf("\"");
+       for (i = 0; i < count; i++) {
+               printf("\\%hho", (unsigned char) (start + i));
+       }
+       printf("\"");
+}
+
+#if DUMPIO_READ || DUMPIO_WRITE
+static void
+dumpstr(unsigned char start, unsigned int count)
+{
+       unsigned int i;
+       unsigned int j;
+
+       for (i = 0; i < count; i++) {
+               if (i < count) {
+                       if (!(i % 16))
+                               printf(" | %05x ", i);
+                       if (!(i % 8))
+                               printf(" ");
+
+                       printf("%02hhx ", (unsigned char) (start + i));
+               }
+
+               if ((i % 16 == 15) || (i == (count - 1))) {
+                       if (i % 16 != 15)
+                               printf("%*s", 3 * (15 - i % 16) +
+                                      ((i + 8) % 16) / 8, " ");
+
+                       printf(" ");
+
+                       for (j = 0; j <= (i % 16); j++)
+                               printf(".");
+                       for (j = i % 16; j < 15; j++)
+                               printf(" ");
+
+                       printf(" |\n");
+
+               }
+       }
+}
+#endif /* DUMPIO_READ || DUMPIO_WRITE */
+
+static void
+cleanup(void)
+{
+       long rc;
+
+       rc = syscall(__NR_mq_unlink, MQ_NAME);
+       printf("mq_unlink(\"" MQ_NAME "\") = %s\n", sprintrc(rc));
+
+       puts("+++ exited with 0 +++");
+}
+
+static void
+do_send(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
+       bool cropped)
+{
+       long rc;
+       long saved_errno;
+
+       do {
+               rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42,
+                            tmout);
+               saved_errno = errno;
+               printf("mq_timedsend(%d, ", fd);
+               printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
+                        msg_size);
+               if (cropped)
+                       printf("...");
+               errno = saved_errno;
+               printf(", %u, 42, {%jd, %jd}) = %s\n", msg_size,
+                      (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
+                      sprintrc(rc));
+               errno = saved_errno;
+
+               if (rc == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       perror_msg_and_skip("mq_timedsend");
+               }
+# if DUMPIO_WRITE
+               dumpstr(MSG_START, msg_size);
+# endif
+       } while (rc);
+}
+
+static void
+do_recv(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
+       bool cropped)
+{
+       long rc;
+       long saved_errno;
+       unsigned prio;
+
+       do {
+               rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio,
+                            tmout);
+               saved_errno = errno;
+               printf("mq_timedreceive(%d, ", fd);
+               if (rc >= 0) {
+                       printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
+                                rc);
+                       if (cropped)
+                               printf("...");
+               } else {
+                       printf("%p", msg);
+               }
+               errno = saved_errno;
+               printf(", %u, [42], {%jd, %jd}) = %s\n", MSG_SIZE,
+                      (intmax_t) tmout->tv_sec,
+                      (intmax_t) tmout->tv_nsec, sprintrc(rc));
+               errno = saved_errno;
+
+               if (rc == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       perror_msg_and_skip("mq_timedreceive");
+               }
+               if ((rc >= 0) && ((unsigned long) rc != msg_size))
+                       error_msg_and_skip("mq_timedreceive size mismatch"
+                                          ": expected %u, got %ld",
+                                          msg_size, rc);
+# if DUMPIO_READ
+               dumpstr(MSG_START, rc);
+# endif
+       } while (rc < 0);
+}
+
+int
+main(void)
+{
+       static const kernel_ulong_t bogus_zero =
+               (kernel_ulong_t) 0x8765432100000000ULL;
+       static const kernel_ulong_t bogus_oflags =
+               (kernel_ulong_t) 0xdefaced100000003ULL;
+       static const kernel_ulong_t bogus_mode =
+               (kernel_ulong_t) 0xdec0deadfacefeedULL;
+       static const kernel_ulong_t bogus_fd =
+               (kernel_ulong_t) 0xfeedfacedeadba5eULL;
+       static const kernel_ulong_t bogus_zero_size =
+               (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 :
+                       (kernel_ulong_t) 0xface1e5500000000ULL;
+       static const kernel_ulong_t bogus_size =
+               (kernel_ulong_t) 0xbadc0dedda7a1057ULL;
+       static const kernel_ulong_t bogus_prio =
+               (kernel_ulong_t) 0xdec0ded1defaced3ULL;
+       static const struct timespec bogus_tmout_data = {
+               .tv_sec = (time_t) 0xdeadfacebeeff00dLL,
+               .tv_nsec = (long) 0xfacefee1deadfeedLL,
+       };
+       static const struct timespec future_tmout_data = {
+               .tv_sec = (time_t) 0x7ea1fade7e57faceLL,
+               .tv_nsec = 999999999,
+       };;
+       struct_sigevent bogus_sev_data = {
+               .sigev_notify = 0xdefaced,
+               .sigev_signo = 0xfacefeed,
+               .sigev_value.sival_ptr = (unsigned long) 0xdeadbeefbadc0ded
+       };
+
+       const char *errstr;
+       long rc;
+       kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) *
+               NUM_ATTRS);
+       char *msg = tail_alloc(MSG_SIZE);
+       unsigned *bogus_prio_ptr = tail_alloc(sizeof(*bogus_prio_ptr));
+       struct timespec *bogus_tmout = tail_memdup(&bogus_tmout_data,
+               sizeof(*bogus_tmout));
+       struct timespec *future_tmout = tail_memdup(&future_tmout_data,
+               sizeof(*future_tmout));
+       struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data,
+               sizeof(*bogus_sev));
+       int fd = -1;
+
+
+       fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE);
+       fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
+                      0xbb, 0x70);
+
+
+       /* mq_open */
+
+       /* Zero values, non-O_CREAT mode */
+       rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL);
+       printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc));
+
+       /* O_CREAT parsing, other flags, bogs values */
+       rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
+                    NULL);
+       printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n",
+              msg, (unsigned short) bogus_mode, sprintrc(rc));
+
+       /* Partially invalid attributes structure */
+       rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
+                    bogus_attrs + 1);
+       printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n",
+              msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc));
+
+       /* Valid attributes structure */
+       rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
+                    bogus_attrs);
+       printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx, "
+              "mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n",
+              msg, (unsigned short) bogus_mode,
+              (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
+              (long long) bogus_attrs[1],
+              (long long) bogus_attrs[2],
+              (long long) bogus_attrs[3], sprintrc(rc));
+
+
+       /* mq_timedsend */
+
+       /* Zero values*/
+       rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size,
+                    bogus_zero, NULL);
+       printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc));
+
+       /* Invalid pointers */
+       rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size,
+                    bogus_prio, bogus_tmout + 1);
+       printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n",
+              (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
+              (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc));
+
+       /* Partially invalid message (memory only partially available) */
+       rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
+                    MSG_SIZE, bogus_prio, bogus_tmout);
+       printf("mq_timedsend(%d, %p, %llu, %u, {%jd, %jd}) = %s\n",
+              (int) bogus_fd, msg + MSG_SIZE - MSG_CUT,
+              (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
+              (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
+              sprintrc(rc));
+
+       /* Fully valid message, uncut */
+       rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
+                    MSG_CUT, bogus_prio, bogus_tmout);
+       errstr = sprintrc(rc);
+       printf("mq_timedsend(%d, ", (int) bogus_fd);
+       printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT);
+       printf(", %llu, %u, {%jd, %jd}) = %s\n",
+              (unsigned long long) MSG_CUT, (unsigned) bogus_prio,
+              (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
+              errstr);
+
+       /* Partially invalid message, cut at maxstrlen */
+       rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE,
+                    bogus_prio, bogus_tmout);
+       errstr = sprintrc(rc);
+       printf("mq_timedsend(%d, ", (int) bogus_fd);
+       printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT);
+       printf("..., %llu, %u, {%jd, %jd}) = %s\n",
+              (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
+              (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
+              errstr);
+
+
+       /* mq_timedreceive */
+
+       /* Zero values */
+       rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size,
+                    NULL, NULL);
+       printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc));
+
+       /* Invalid addresses */
+       rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size,
+                    bogus_prio_ptr + 1, bogus_tmout + 1);
+       printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n",
+              (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
+              bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc));
+
+       /* Invalid fd, valid msg pointer */
+       rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size,
+                    bogus_prio_ptr, bogus_tmout);
+       printf("mq_timedreceive(%d, %p, %llu, %p, {%jd, %jd}) = %s\n",
+              (int) bogus_fd, msg, (unsigned long long) bogus_size,
+              bogus_prio_ptr, (intmax_t) bogus_tmout->tv_sec,
+              (intmax_t) bogus_tmout->tv_nsec, sprintrc(rc));
+
+
+       /* mq_notify */
+
+       /* Zero values */
+       rc = syscall(__NR_mq_notify, bogus_zero, NULL);
+       printf("mq_notify(0, NULL) = %s\n", sprintrc(rc));
+
+       /* Invalid pointer */
+       rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1);
+       printf("mq_notify(%d, %p) = %s\n",
+              (int) bogus_fd, bogus_sev + 1, sprintrc(rc));
+
+       /* Invalid SIGEV_* */
+       rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
+       printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}"
+              ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n",
+              (int) bogus_fd, bogus_sev->sigev_value.sival_int,
+              bogus_sev->sigev_value.sival_ptr,
+              bogus_sev->sigev_signo, bogus_sev->sigev_notify,
+              sprintrc(rc));
+
+       /* SIGEV_NONE */
+       bogus_sev->sigev_notify = SIGEV_NONE;
+       rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
+       printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, "
+              "sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n",
+              (int) bogus_fd, bogus_sev->sigev_value.sival_int,
+              bogus_sev->sigev_value.sival_ptr,
+              bogus_sev->sigev_signo, sprintrc(rc));
+
+       /* SIGEV_SIGNAL */
+       bogus_sev->sigev_notify = SIGEV_SIGNAL;
+       bogus_sev->sigev_signo = SIGALRM;
+       rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
+       printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, "
+              "sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n",
+              (int) bogus_fd, bogus_sev->sigev_value.sival_int,
+              bogus_sev->sigev_value.sival_ptr, sprintrc(rc));
+
+       /* SIGEV_THREAD */
+       bogus_sev->sigev_notify = SIGEV_THREAD;
+       bogus_sev->sigev_un.sigev_thread.function =
+               (unsigned long) 0xdeadbeefbadc0ded;
+       bogus_sev->sigev_un.sigev_thread.attribute =
+               (unsigned long) 0xcafef00dfacefeed;
+       rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
+       printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, "
+              "sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD, "
+              "sigev_notify_function=%#lx, sigev_notify_attributes=%#lx}) = "
+              "%s\n",
+              (int) bogus_fd, bogus_sev->sigev_value.sival_int,
+              bogus_sev->sigev_value.sival_ptr,
+              bogus_sev->sigev_un.sigev_thread.function,
+              bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc));
+
+       /* mq_unlink */
+
+       /* Zero values */
+       rc = syscall(__NR_mq_unlink, NULL);
+       printf("mq_unlink(NULL) = %s\n", sprintrc(rc));
+
+       /* Invalid ptr */
+       rc = syscall(__NR_mq_unlink, msg + MSG_SIZE);
+       printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc));
+
+       /* Long unterminated string */
+       rc = syscall(__NR_mq_unlink, msg);
+       errstr = sprintrc(rc);
+       printf("mq_unlink(%p) = %s\n", msg, errstr);
+
+
+       /* Sending and receiving test */
+
+# if DUMPIO_READ || DUMPIO_WRITE
+       close(0);
+# endif
+       bogus_attrs[1] = 2;
+       bogus_attrs[2] = MSG_SIZE;
+       fd = rc = syscall(__NR_mq_open, MQ_NAME,
+                         O_CREAT|O_RDWR|O_NONBLOCK, S_IRWXU, bogus_attrs);
+       errstr = sprintrc(rc);
+       if (rc < 0)
+               perror_msg_and_skip("mq_open");
+       else
+               atexit(cleanup);
+# if DUMPIO_READ || DUMPIO_WRITE
+       if (fd != 0)
+               error_msg_and_skip("mq_open returned fd other than 0");
+# endif
+       fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
+                      0xbb, 0x70);
+       printf("mq_open(\"" MQ_NAME "\", O_RDWR|O_CREAT|O_NONBLOCK, "
+              "0700, {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u, "
+              "mq_curmsgs=%lld}) = %s\n",
+              (unsigned long long) (kernel_ulong_t) bogus_attrs[0], MSG_SIZE,
+              (long long) bogus_attrs[3], errstr);
+
+       rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs);
+       if (rc < 0)
+               perror_msg_and_skip("mq_getsetattr");
+       if ((bogus_attrs[1] < 2) || (bogus_attrs[2] < MSG_SIZE))
+               error_msg_and_skip("mq too small");
+
+       do_send(fd, msg, MSG_CUT, future_tmout, false);
+       do_send(fd, msg, MSG_SIZE, future_tmout, true);
+
+       memset(msg, '\0', MSG_SIZE);
+       do_recv(fd, msg, MSG_CUT, future_tmout, false);
+
+       memset(msg, '\0', MSG_SIZE);
+       do_recv(fd, msg, MSG_SIZE, future_tmout, true);
+
+       return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_mq_open && __NR_mq_timedsend && "
+       "__NR_mq_timedreceive && __NR_mq_notify && __NR_mq_unlink");
+
+#endif
diff --git a/tests/mq_sendrecv.test b/tests/mq_sendrecv.test
new file mode 100755 (executable)
index 0000000..67f4d63
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check decoding of mq_open, mq_notify, mq_timedsend, mq_timedreceive syscalls.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -e trace=mq_open,mq_notify,mq_timedsend,mq_timedreceive,mq_unlink -a14