Browse Source

pipecmd: fix fd leak.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 10 years ago
parent
commit
dd204de80d
2 changed files with 46 additions and 0 deletions
  1. 2 0
      ccan/pipecmd/pipecmd.c
  2. 44 0
      ccan/pipecmd/test/run-fdleak.c

+ 2 - 0
ccan/pipecmd/pipecmd.c

@@ -101,10 +101,12 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, char *const *arr)
 	close(execfail[1]);
 	close(execfail[1]);
 	/* Child will close this without writing on successful exec. */
 	/* Child will close this without writing on successful exec. */
 	if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
 	if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) {
+		close(execfail[0]);
 		waitpid(childpid, NULL, 0);
 		waitpid(childpid, NULL, 0);
 		errno = err;
 		errno = err;
 		return -1;
 		return -1;
 	}
 	}
+	close(execfail[0]);
 	if (fd_tochild)
 	if (fd_tochild)
 		*fd_tochild = tochild[1];
 		*fd_tochild = tochild[1];
 	if (fd_fromchild)
 	if (fd_fromchild)

+ 44 - 0
ccan/pipecmd/test/run-fdleak.c

@@ -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();
+}