Commit 9d9b0720f5

LemonBoy <thatlemon@gmail.com>
2019-12-16 10:57:29
Fix for the error codepath in ChildProcess
1 parent c257f89
Changed files (1)
lib/std/child_process.zig
@@ -282,17 +282,36 @@ pub const ChildProcess = struct {
     fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
         defer destroyPipe(self.err_pipe);
 
-        // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
-        // waitpid, so this write is guaranteed to be after the child
-        // pid potentially wrote an error. This way we can do a blocking
-        // read on the error pipe and either get maxInt(ErrInt) (no error) or
-        // an error code.
-        try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
-        const err_int = try readIntFd(self.err_pipe[0]);
-        // Here we potentially return the fork child's error
-        // from the parent pid.
-        if (err_int != maxInt(ErrInt)) {
-            return @errSetCast(SpawnError, @intToError(err_int));
+        if (builtin.os == .linux) {
+            var fd = [1]std.os.pollfd{std.os.pollfd{
+                .fd = self.err_pipe[0],
+                .events = std.os.POLLIN,
+                .revents = undefined,
+            }};
+
+            // Check if the eventfd buffer stores a non-zero value by polling
+            // it, that's the error code returned by the child process.
+            _ = std.os.poll(&fd, 0) catch unreachable;
+
+            // According to eventfd(2) the descriptro is readable if the counter
+            // has a value greater than 0
+            if ((fd[0].revents & std.os.POLLIN) != 0) {
+                const err_int = try readIntFd(self.err_pipe[0]);
+                return @errSetCast(SpawnError, @intToError(err_int));
+            }
+        } else {
+            // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
+            // waitpid, so this write is guaranteed to be after the child
+            // pid potentially wrote an error. This way we can do a blocking
+            // read on the error pipe and either get maxInt(ErrInt) (no error) or
+            // an error code.
+            try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
+            const err_int = try readIntFd(self.err_pipe[0]);
+            // Here we potentially return the fork child's error from the parent
+            // pid.
+            if (err_int != maxInt(ErrInt)) {
+                return @errSetCast(SpawnError, @intToError(err_int));
+            }
         }
 
         return statusToTerm(status);