]> granicus.if.org Git - strace/commitdiff
Close stdin/out after child is forked
authorDenys Vlasenko <dvlasenk@redhat.com>
Mon, 8 Feb 2016 13:52:32 +0000 (14:52 +0100)
committerDenys Vlasenko <dvlasenk@redhat.com>
Mon, 8 Feb 2016 17:17:38 +0000 (18:17 +0100)
Testcase:

{ sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9'

The writer (head) will be able to perform writes to write end of the pipe.
With strace call removed, head will immediately get SIGPIPE.

This change fixes this: now writer immediately gets SIGPIPE with strace too.

* strace.c (startup_child): Close stdin/out and reopen them to /dev/null.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
strace.c

index 614b85f9bf0282e48e794bb1e3260301248087e4..35a04237c1510f47689307417cb842b0f2595344 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -1353,6 +1353,27 @@ startup_child(char **argv)
                 * to create a genuine separate stack and execute on it.
                 */
        }
+       /*
+        * A case where straced process is part of a pipe:
+        * { sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9'
+        * If strace won't close its fd#0, closing it in tracee is not enough:
+        * the pipe is still open, it has a reader. Thus, "head" will not get its
+        * SIGPIPE at once, on the first write.
+        *
+        * Preventing it by closing strace's stdin/out.
+        * (Don't leave fds 0 and 1 closed, this is bad practice: future opens
+        * will reuse them, unexpectedly making a newly opened object "stdin").
+        */
+       close(0);
+       if (open("/dev/null", O_RDWR) != 0) /* /dev not populated? */
+               if (open("/", O_RDONLY) != 0) /* shouldn't happen... */
+                       perror_msg_and_die("Can't open '/'");
+       dup2(0, 1);
+#if 0
+       /* A good idea too, but we sometimes need to print error messages */
+       if (shared_log != stderr)
+               dup2(0, 2);
+#endif
 }
 
 #if USE_SEIZE