]> granicus.if.org Git - strace/commitdiff
tests: check decoding of threads when a non-leader thread invokes execve
authorDmitry V. Levin <ldv@altlinux.org>
Mon, 28 Nov 2016 00:31:59 +0000 (00:31 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 28 Nov 2016 00:31:59 +0000 (00:31 +0000)
* tests/threads-execve.c: New file.
* tests/threads-execve.test: New test.
* tests/.gitignore: Add threads-execve.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(threads_execve_LDADD): New variable.
(MISC_TESTS): Add threads-execve.test.

tests/.gitignore
tests/Makefile.am
tests/threads-execve.c [new file with mode: 0644]
tests/threads-execve.test [new file with mode: 0755]

index ebd626fbab66f6a1e25da4636b2024c3f4e999b3..2970f649dda99cc6e2e912b3db86473a1fe12da4 100644 (file)
@@ -315,6 +315,7 @@ sync_file_range2
 sysinfo
 syslog
 tee
+threads-execve
 time
 timer_create
 timer_xettime
index 24f29cbfb7b94d295051ca3f68fb3e9e4d1a4b29..454284968a043c08c67d57361d4cb89a898c9af9 100644 (file)
@@ -373,6 +373,7 @@ check_PROGRAMS = \
        sysinfo \
        syslog \
        tee \
+       threads-execve \
        time \
        timer_create \
        timer_xettime \
@@ -436,6 +437,7 @@ preadv_pwritev_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 pwritev_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 stat64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 statfs_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
+threads_execve_LDADD = -lrt -lpthread $(LDADD)
 times_LDADD = -lrt $(LDADD)
 truncate64_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
 uio_CPPFLAGS = $(AM_CPPFLAGS) -D_FILE_OFFSET_BITS=64
@@ -815,6 +817,7 @@ MISC_TESTS = \
        strace-t.test \
        strace-tt.test \
        strace-ttt.test \
+       threads-execve.test \
        vfork-f.test \
        # end of MISC_TESTS
 
diff --git a/tests/threads-execve.c b/tests/threads-execve.c
new file mode 100644 (file)
index 0000000..c3faa14
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Check decoding of threads when a non-leader thread invokes execve.
+ *
+ * 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 <asm/unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+static pid_t leader;
+static pid_t tid;
+
+static void
+handler(int signo)
+{
+}
+
+static unsigned int sigsetsize;
+static long
+k_sigsuspend(const sigset_t *const set)
+{
+       return syscall(__NR_rt_sigsuspend, set, sigsetsize);
+}
+
+static pid_t
+k_gettid(void)
+{
+       return syscall(__NR_gettid);
+}
+
+static void
+get_sigsetsize(void)
+{
+       static const struct sigaction sa = { .sa_handler = handler };
+       if (sigaction(SIGUSR1, &sa, NULL))
+               perror_msg_and_fail("sigaction");
+
+       sigset_t mask;
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGUSR1);
+       if (sigprocmask(SIG_BLOCK, &mask, NULL))
+               perror_msg_and_fail("sigprocmask");
+
+       raise(SIGUSR1);
+
+       sigemptyset(&mask);
+       for (sigsetsize = sizeof(mask) / sizeof(long);
+            sigsetsize; sigsetsize >>= 1) {
+               long rc = k_sigsuspend(&mask);
+               if (!rc)
+                       error_msg_and_fail("rt_sigsuspend");
+               if (EINTR == errno)
+                       break;
+               printf("%-5d rt_sigsuspend(%p, %u) = %s\n",
+                      leader, &mask, sigsetsize, sprintrc(rc));
+       }
+       if (!sigsetsize)
+               perror_msg_and_fail("rt_sigsuspend");
+       printf("%-5d rt_sigsuspend([], %u) = ? ERESTARTNOHAND"
+              " (To be restarted if no handler)\n", leader, sigsetsize);
+}
+
+enum {
+       ACTION_exit = 0,
+       ACTION_rt_sigsuspend,
+       ACTION_nanosleep,
+       NUMBER_OF_ACTIONS
+};
+
+static const unsigned int NUMBER_OF_ITERATIONS = 4;
+static unsigned int action;
+static int fds[2];
+
+static unsigned int
+arglen(char **args)
+{
+       char **p;
+
+       for (p = args; *p; ++p)
+               ;
+
+       return p - args;
+}
+
+static void *
+thread(void *arg)
+{
+       tid = k_gettid();
+
+       static char buf[sizeof(action) * 3];
+       sprintf(buf, "%u", action + 1);
+
+       char **argv = arg;
+       argv[2] = buf;
+
+       if (read(fds[0], fds, sizeof(fds[0])))
+               perror_msg_and_fail("execve");
+
+       struct timespec ts = { .tv_nsec = 100000000 };
+       (void) clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL);
+
+       ts.tv_nsec = 12345;
+       printf("%-5d nanosleep({tv_sec=0, tv_nsec=%u}, NULL) = 0\n",
+              tid, (unsigned int) ts.tv_nsec);
+
+       switch (action % NUMBER_OF_ACTIONS) {
+               case ACTION_exit:
+                       printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
+                              ", [/* %u vars */] <pid changed to %u ...>\n",
+                              tid, argv[0], argv[0], argv[1], argv[2],
+                              arglen(environ), leader);
+                       break;
+               case ACTION_rt_sigsuspend:
+                       printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
+                              ", [/* %u vars */] <unfinished ...>\n"
+                              "%-5d <... rt_sigsuspend resumed>) = ?\n",
+                              tid, argv[0], argv[0], argv[1], argv[2],
+                              arglen(environ),
+                              leader);
+                       break;
+               case ACTION_nanosleep:
+                       printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
+                              ", [/* %u vars */] <unfinished ...>\n"
+                              "%-5d <... nanosleep resumed> <unfinished ...>)"
+                              " = ?\n",
+                              tid, argv[0], argv[0], argv[1], argv[2],
+                              arglen(environ),
+                              leader);
+                       break;
+       }
+
+       printf("%-5d +++ superseded by execve in pid %u +++\n"
+              "%-5d <... execve resumed> ) = 0\n",
+              leader, tid,
+              leader);
+
+       (void) nanosleep(&ts, NULL);
+       execve(argv[0], argv, environ);
+       perror_msg_and_fail("execve");
+}
+
+int
+main(int ac, char **av)
+{
+       setvbuf(stdout, NULL, _IONBF, 0);
+       leader = getpid();
+
+       if (ac < 3) {
+               struct timespec ts = { .tv_nsec = 1 };
+               if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL))
+                       perror_msg_and_skip("clock_nanosleep CLOCK_REALTIME");
+
+               printf("%-5d execve(\"%s\", [\"%s\"], [/* %u vars */]) = 0\n",
+                      leader, av[0], av[0], arglen(environ));
+
+               get_sigsetsize();
+               static char buf[sizeof(sigsetsize) * 3];
+               sprintf(buf, "%u", sigsetsize);
+
+               char *argv[] = { av[0], buf, (char *) "0", NULL };
+               printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
+                      ", [/* %u vars */]) = 0\n",
+                      leader, argv[0], argv[0], argv[1], argv[2],
+                      arglen(environ));
+               execve(argv[0], argv, environ);
+               perror_msg_and_fail("execve");
+       }
+
+       sigsetsize = atoi(av[1]);
+       action = atoi(av[2]);
+
+       if (action >= NUMBER_OF_ACTIONS * NUMBER_OF_ITERATIONS) {
+               printf("%-5d +++ exited with 0 +++\n", leader);
+               return 0;
+       }
+
+       if (pipe(fds))
+               perror_msg_and_fail("pipe");
+
+       pthread_t t;
+       errno = pthread_create(&t, NULL, thread, av);
+       if (errno)
+               perror_msg_and_fail("pthread_create");
+
+       struct timespec ts = { .tv_sec = 123 };
+       sigset_t mask;
+       sigemptyset(&mask);
+
+       switch (action % NUMBER_OF_ACTIONS) {
+               case ACTION_exit:
+                       printf("%-5d exit(42)       = ?\n", leader);
+                       close(fds[1]);
+                       (void) syscall(__NR_exit, 42);
+                       break;
+               case ACTION_rt_sigsuspend:
+                       printf("%-5d rt_sigsuspend([], %u <unfinished ...>\n",
+                              leader, sigsetsize);
+                       close(fds[1]);
+                       (void) k_sigsuspend(&mask);
+                       break;
+               case ACTION_nanosleep:
+                       printf("%-5d nanosleep({tv_sec=%u, tv_nsec=0}"
+                              ",  <unfinished ...>\n",
+                              leader, (unsigned int) ts.tv_sec);
+                       close(fds[1]);
+                       (void) nanosleep(&ts, 0);
+                       break;
+       }
+
+       return 1;
+}
diff --git a/tests/threads-execve.test b/tests/threads-execve.test
new file mode 100755 (executable)
index 0000000..49d69b5
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Check decoding of threads when a non-leader thread invokes execve.
+#
+# 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"
+
+# Check that PTRACE_EVENT_EXEC support in kernel is good enough.
+# The kernel before commit v3.1-rc1~308^2~7 reported 0 instead of old pid.
+uname_r="$(uname -r)"
+case "$uname_r" in
+       3.[2-9]*|3.1[0-9]*|[4-9].*|[123][0-9]*) ;;
+       *) skip_ "the kernel release $uname_r is not 3.1 or newer" ;;
+esac
+
+run_strace_match_diff -a21 \
+       -f -esignal=none -e trace=execve,exit,nanosleep,rt_sigsuspend