pipecmd: fix fd leak.
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 19 Jan 2016 03:13:07 +0000 (13:43 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 19 Jan 2016 03:13:07 +0000 (13:43 +1030)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/pipecmd/pipecmd.c
ccan/pipecmd/test/run-fdleak.c [new file with mode: 0644]

index 671d39198089b424f00e3f5041a7d79291ec55f8..c97fa312396dbb728e9cdceb6b795e21f6ee33da 100644 (file)
@@ -101,10 +101,12 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
        close(execfail[1]);
        /* Child will close this without writing on successful exec. */
        if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
+               close(execfail[0]);
                waitpid(childpid, NULL, 0);
                errno = err;
                return -1;
        }
+       close(execfail[0]);
        if (fd_tochild)
                *fd_tochild = tochild[1];
        if (fd_fromchild)
diff --git a/ccan/pipecmd/test/run-fdleak.c b/ccan/pipecmd/test/run-fdleak.c
new file mode 100644 (file)
index 0000000..9ab9d1b
--- /dev/null
@@ -0,0 +1,44 @@
+#include <ccan/pipecmd/pipecmd.h>
+/* Include the C files directly. */
+#include <ccan/pipecmd/pipecmd.c>
+#include <ccan/tap/tap.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(int argc, char *argv[])
+{
+       pid_t child;
+       int outfd, status;
+       char buf[5] = "test";
+
+       /* We call ourselves, to test pipe. */
+       if (argc == 2) {
+               if (write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf))
+                               exit(1);
+               exit(0);
+       }
+
+       /* This is how many tests you plan to run */
+       plan_tests(13);
+       child = pipecmd(&outfd, NULL, argv[0], "out", NULL);
+       if (!ok1(child > 0))
+               exit(1);
+       ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf));
+       ok1(memcmp(buf, "test", sizeof(buf)) == 0);
+       ok1(waitpid(child, &status, 0) == child);
+       ok1(WIFEXITED(status));
+       ok1(WEXITSTATUS(status) == 0);
+
+       /* No leaks! */
+       ok1(close(outfd) == 0);
+       ok1(close(outfd) == -1 && errno == EBADF);
+       ok1(close(++outfd) == -1 && errno == EBADF);
+       ok1(close(++outfd) == -1 && errno == EBADF);
+       ok1(close(++outfd) == -1 && errno == EBADF);
+       ok1(close(++outfd) == -1 && errno == EBADF);
+       ok1(close(++outfd) == -1 && errno == EBADF);
+
+       /* This exits depending on whether all tests passed */
+       return exit_status();
+}