shithub: mc

Download patch

ref: 9cb3a0f22ac95f75e87e944b95b6c5a13a4eb729
parent: f8b121ae9b3e57bbca8304676d417f680ad26f7a
author: Ori Bernstein <ori@markovcorp.com>
date: Thu Feb 15 06:19:03 EST 2018

Be a bit better about cleaning up fds on error.

--- a/lib/std/spork.myr
+++ b/lib/std/spork.myr
@@ -33,14 +33,17 @@
 	var infds : fd[2], outfds : fd[2]
 	var err
 
+	/* init for safe close */
+	infds = [-1, -1]
+	outfds = [-1, -1]
 	/* open up pipes */
 	err = pipe(&infds) 
 	if err != Enone
-		-> `Err err
+		goto sporkerr
 	;;
 	err = pipe(&outfds)
 	if err != Enone
-		-> `Err err
+		goto sporkerr
 	;;
 
 	match sporkfd(cmd, infds, outfds, [-1, 2])
@@ -50,8 +53,15 @@
 		close(outfds[1]);
 		-> `Ok (pid, infds[1], outfds[0])
 	| `Err m:
-		-> `Err m
+		err = m
+		goto sporkerr
 	;;
+:sporkerr
+	close(infds[0])
+	close(infds[1])
+	close(outfds[0])
+	close(outfds[1])
+	-> `Err err
 }
 
 const espork = {cmd
@@ -58,18 +68,22 @@
 	var infds : fd[2], outfds : fd[2], errfds : fd[2]
 	var err
 
+	/* init for safe close */
+	infds = [-1, -1]
+	outfds = [-1, -1]
+	errfds = [-1, -1]
 	/* open up pipes */
 	err = pipe(&infds) 
 	if err != Enone
-		-> `Err err
+		goto sporkerr
 	;;
 	err = pipe(&outfds)
 	if err != Enone
-		-> `Err err
+		goto sporkerr
 	;;
 	err = pipe(&errfds)
 	if err != Enone
-		-> `Err err
+		goto sporkerr
 	;;
 
 	match sporkfd(cmd, infds, outfds, errfds)
@@ -80,8 +94,18 @@
 		close(errfds[1]);
 		-> `Ok (pid, infds[1], outfds[0], errfds[0])
 	| `Err m:
-		-> `Err m
+		err = m
+		goto sporkerr
 	;;
+:sporkerr
+	/* close on a bad fd is ok. */
+	close(infds[0])
+	close(infds[1])
+	close(outfds[0])
+	close(outfds[1])
+	close(errfds[0])
+	close(errfds[1])
+	-> `Err err
 }
 
 const filterfd = {fd, cmd
@@ -110,13 +134,20 @@
 	pid = fork()
 	/* error  */
 	if pid < 0
-		/* we don't want to leak the pipe fds on error */
-		close(infds[0]);
-		close(infds[1]);
-		close(outfds[0]);
-		close(outfds[1]);
-		close(errfds[0]);
-		close(errfds[1]);
+		/*
+		  so we don't leak fds on error,
+		  close the child's ends. The parent
+		  handles closing its fds.
+		*/
+		if infds[1] != 0
+			close(infds[1]);
+		;;
+		if outfds[0] != 1
+			close(outfds[0]);
+		;;
+		if errfds[0] != 2
+			close(errfds[0]);
+		;;
 		-> `Err (pid : errno)
 	/* child */
 	elif pid == 0
--- a/support/syscall-gen/specials+linux-x64.frag
+++ b/support/syscall-gen/specials+linux-x64.frag
@@ -19,7 +19,7 @@
 			fn : void#  /* we need a raw pointer */ \
 			-> pid)
 const wait4	: (pid:pid, loc:int32#, opt : int64, usage:rusage#	-> int64)
-const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+const waitpid	: (pid:pid, loc:int32#, opt : int64	-> pid)
 const execv	: (cmd : byte[:], args : byte[:][:] -> int64)
 const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
 /* wrappers to extract wait status */
@@ -119,7 +119,7 @@
 const wait4	= {pid, loc, opt, usage;	-> syscall(Syswait4, a(pid), a(loc), a(opt), a(usage))}
 const waitpid	= {pid, loc, opt;
 	var rusage
-	-> wait4(pid, loc, opt, &rusage)
+	-> (wait4(pid, loc, opt, &rusage) : pid)
 }
 
 const execv	= {cmd, args