[patch] Multithreaded process left Stopped (T) on CTRL-C of strace

Jan Kratochvil jan.kratochvil at redhat.com
Thu Jun 14 22:16:02 UTC 2007


On Wed, 13 Jun 2007 04:34:15 +0200, Roland McGrath wrote:
> > Thank's this was a good idea, included the testcase and fixed the code
> > appropriately.  Neither PTRACE_KILL nor SIGKILL work but SIGSTOP looks
> > fine for the leader task.  I only hope there is no race.
> 
> I am not very confident about this SIGSTOP you introduced.  What we've been
> discussing, and AFAIK what you have tested thoroughly here, is the
> TCB_EXITING case, so the introduction of SIGSTOP is speculative.

Is this patch OK for the first - safe - part?

It no longer writes multiple "detached" messages for this TCB_EXITING case.


Regards,
Jan
-------------- next part --------------
2007-06-14  Jan Kratochvil  <jan.kratochvil at redhat.com>

	* strace.c (detach): New prototype.  Extended the function comment.
	[LINUX] (detach): Call droptcb() instead of the wrongly parametrized
	detach() call.
	(handle_group_exit): Call droptcb() instead of the wrongly parametrized
	detach() call.  Always call detach() only once from the group leader.
	Comment the leader killing known bug tested by `test/leaderkill.c'.
	Code advisory: Roland McGrath
	Fixes RH#240961.
	* test/leaderkill.c: New file.
	* test/.cvsignore, test/Makefile: Added `test/leaderkill.c'.

Index: strace.c
===================================================================
RCS file: /cvsroot/strace/strace/strace.c,v
retrieving revision 1.77
diff -u -p -r1.77 strace.c
--- strace.c	11 Jun 2007 22:06:31 -0000	1.77
+++ strace.c	14 Jun 2007 17:40:39 -0000
@@ -98,6 +98,7 @@ unsigned int nprocs, tcbtabsize;
 char *progname;
 extern char **environ;
 
+static int detach P((struct tcb *tcp, int sig));
 static int trace P((void));
 static void cleanup P((void));
 static void interrupt P((int sig));
@@ -1332,7 +1333,10 @@ struct tcb *tcp;
 
 #endif /* !USE_PROCFS */
 
-/* detach traced process; continue with sig */
+/* detach traced process; continue with sig
+   Never call DETACH twice on the same process as both unattached and
+   attached-unstopped processes give the same ESRCH.  For unattached process we
+   would SIGSTOP it and wait for its SIGSTOP notification forever.  */
 
 static int
 detach(tcp, sig)
@@ -1521,8 +1525,10 @@ int sig;
 	droptcb(tcp);
 
 #ifdef LINUX
-	if (zombie != NULL)
-		error = detach(zombie) || error;
+	if (zombie != NULL) {
+		/* TCP no longer exists therefore you must not detach () it.  */
+		droptcb(zombie);
+	}
 #endif
 
 	return error;
@@ -2096,7 +2102,8 @@ handle_group_exit(struct tcb *tcp, int s
 			fprintf(stderr,
 				"PANIC: handle_group_exit: %d leader %d\n",
 				tcp->pid, leader ? leader->pid : -1);
-		detach(tcp);	/* Already died.  */
+		/* TCP no longer exists therefore you must not detach () it.  */
+		droptcb(tcp);	/* Already died.  */
 	}
 	else {
 		/* Mark that we are taking the process down.  */
@@ -2115,13 +2122,17 @@ handle_group_exit(struct tcb *tcp, int s
 					   stopped.  Then the value we pass
 					   in PTRACE_DETACH just sets the
 					   death signal reported to the
-					   real parent.  */
+					   real parent.
+					   FIXME: This killing gets caught by
+					   WAITPID of the leader's parent.
+					   Testcase: test/leaderkill.c  */
 					ptrace(PTRACE_KILL, leader->pid, 0, 0);
 					if (debug)
 						fprintf(stderr,
 							" [%d exit %d kills %d]\n",
 							tcp->pid, sig, leader->pid);
-					detach(leader, sig);
+					if (!(leader->flags & TCB_EXITING))
+						detach(leader, sig);
 				}
 				else
 					leader->flags |= TCB_GROUP_EXITING;
Index: test/.cvsignore
===================================================================
RCS file: /cvsroot/strace/strace/test/.cvsignore,v
retrieving revision 1.2
diff -u -p -r1.2 .cvsignore
--- test/.cvsignore	3 Sep 2000 23:38:17 -0000	1.2
+++ test/.cvsignore	14 Jun 2007 17:40:40 -0000
@@ -3,3 +3,4 @@ sig
 skodic
 vfork
 clone
+leaderkill
Index: test/Makefile
===================================================================
RCS file: /cvsroot/strace/strace/test/Makefile,v
retrieving revision 1.4
diff -u -p -r1.4 Makefile
--- test/Makefile	10 Apr 2000 22:22:33 -0000	1.4
+++ test/Makefile	14 Jun 2007 17:40:40 -0000
@@ -2,8 +2,10 @@
 # $Id: Makefile,v 1.4 2000/04/10 22:22:33 wakkerma Exp $
 #
 
-all: vfork fork sig skodic clone
+all: vfork fork sig skodic clone leaderkill
+
+leaderkill: LDFLAGS += -pthread
 
 clean distclean:
-	rm -f clone vfork fork sig *.o core
+	rm -f clone vfork fork sig leaderkill *.o core
 
Index: test/leaderkill.c
===================================================================
RCS file: test/leaderkill.c
diff -N test/leaderkill.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ test/leaderkill.c	14 Jun 2007 17:40:40 -0000
@@ -0,0 +1,59 @@
+/* Test handle_group_exit () handling of a thread leader still alive with its
+ * thread child calling exit_group () and proper passing of the process exit
+ * code to the process parent of this whole thread group.
+ * 
+ * gcc -o test/leaderkill test/leaderkill.c -Wall -ggdb2 -pthread;./test/leaderkill & pid=$!;sleep 1;strace -o x -q ./strace -f -p $pid
+ * It must print: write(1, "OK\n", ...
+ */
+
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+static void *start (void *arg)
+{
+  sleep (1);
+
+  exit (42);
+}
+
+int main (void)
+{
+  pthread_t thread1;
+  int i;
+  pid_t child, got_pid;
+  int status;
+
+  sleep (2);
+
+  child = fork ();
+  switch (child)
+    {
+      case -1:
+	abort ();
+      case 0:
+	i = pthread_create (&thread1, NULL, start, NULL);
+	assert (i == 0);
+/* Two possible testcases; the second one passed even in the older versions.  */
+#if 1
+	pause ();
+#else
+	pthread_exit (NULL);
+#endif
+	/* NOTREACHED */
+	abort ();
+	break;
+      default:
+	got_pid = waitpid (child, &status, 0);
+	assert (got_pid == child);
+	assert (WIFEXITED (status));
+	assert (WEXITSTATUS (status) == 42);
+	puts ("OK");
+	exit (0);
+    }
+  /* NOTREACHED */
+  abort ();
+}


More information about the Strace-devel mailing list