2424#include < fcntl.h>
2525#include < poll.h>
2626#include < spawn.h>
27+ #include < sys/socket.h>
28+ #include < sys/types.h>
2729#include < sys/wait.h>
2830#include < unistd.h>
2931#endif // !defined(_MSC_VER)
@@ -64,9 +66,9 @@ class SubProcess {
6466 absl::Duration timeout);
6567
6668 private:
67- void CreatePipes ();
68- void CloseChildPipes ();
69- void CloseParentPipes ();
69+ void CreateCommunicationFds ();
70+ void CloseChildFds ();
71+ void CloseParentFds ();
7072 posix_spawn_file_actions_t CreateChildFileActions ();
7173 void StartWatchdog (absl::Duration timeout);
7274 pid_t StartChild (
@@ -77,36 +79,41 @@ class SubProcess {
7779 // Pipe file descriptors pairs. Index 0 is for stdout, index 1 is for stderr.
7880 static constexpr int kStdOutIdx = 0 ;
7981 static constexpr int kStdErrIdx = 1 ;
80- int parent_pipe_ [2 ];
81- int child_pipe_ [2 ];
82+ int parent_fds_ [2 ];
83+ int child_fds_ [2 ];
8284};
8385
84- // Creates parent/child pipes for piping stdout/stderr from child to parent.
85- void SubProcess::CreatePipes () {
86+ // Creates communication fds for passing through stdout/stderr from child to
87+ // parent.
88+ void SubProcess::CreateCommunicationFds () {
8689 for (int channel : {kStdOutIdx , kStdErrIdx }) {
87- int pipe_fds [2 ];
88- FUZZTEST_INTERNAL_CHECK (pipe (pipe_fds ) == 0 ,
89- " Cannot create pipe : " , strerror (errno));
90+ int fds [2 ];
91+ FUZZTEST_INTERNAL_CHECK (socketpair (AF_UNIX, SOCK_STREAM, 0 , fds ) == 0 ,
92+ " Cannot create socketpair : " , strerror (errno));
9093
91- parent_pipe_[channel] = pipe_fds[0 ];
92- child_pipe_[channel] = pipe_fds[1 ];
94+ parent_fds_[channel] = fds[0 ];
95+ child_fds_[channel] = fds[1 ];
96+ FUZZTEST_INTERNAL_CHECK (shutdown (fds[0 ], SHUT_WR) == 0 ,
97+ " Cannot shutdown fds: " , strerror (errno));
98+ FUZZTEST_INTERNAL_CHECK (shutdown (fds[1 ], SHUT_RD) == 0 ,
99+ " Cannot shutdown fds: " , strerror (errno));
93100
94101 FUZZTEST_INTERNAL_CHECK (
95- fcntl (parent_pipe_ [channel], F_SETFL, O_NONBLOCK) != -1 ,
96- " Cannot make pipe non-blocking: " , strerror (errno));
102+ fcntl (parent_fds_ [channel], F_SETFL, O_NONBLOCK) != -1 ,
103+ " Cannot make communication fds non-blocking: " , strerror (errno));
97104 }
98105}
99106
100- void SubProcess::CloseChildPipes () {
107+ void SubProcess::CloseChildFds () {
101108 for (int channel : {kStdOutIdx , kStdErrIdx }) {
102- FUZZTEST_INTERNAL_CHECK (close (child_pipe_ [channel]) != -1 ,
109+ FUZZTEST_INTERNAL_CHECK (close (child_fds_ [channel]) != -1 ,
103110 " Cannot close pipe: " , strerror (errno));
104111 }
105112}
106113
107- void SubProcess::CloseParentPipes () {
114+ void SubProcess::CloseParentFds () {
108115 for (int channel : {kStdOutIdx , kStdErrIdx }) {
109- FUZZTEST_INTERNAL_CHECK (close (parent_pipe_ [channel]) != -1 ,
116+ FUZZTEST_INTERNAL_CHECK (close (parent_fds_ [channel]) != -1 ,
110117 " Cannot close pipe: " , strerror (errno));
111118 }
112119}
@@ -128,16 +135,16 @@ posix_spawn_file_actions_t SubProcess::CreateChildFileActions() {
128135
129136 for (int channel : {kStdOutIdx , kStdErrIdx }) {
130137 // Close parent-side pipes.
131- err = posix_spawn_file_actions_addclose (&actions, parent_pipe_ [channel]);
138+ err = posix_spawn_file_actions_addclose (&actions, parent_fds_ [channel]);
132139 FUZZTEST_INTERNAL_CHECK (err == 0 ,
133140 " Cannot add close() action: " , strerror (err));
134141
135142 // Replace stdout/stderr file descriptors with the pipes.
136143 int fd = channel == kStdOutIdx ? STDOUT_FILENO : STDERR_FILENO;
137- err = posix_spawn_file_actions_adddup2 (&actions, child_pipe_ [channel], fd);
144+ err = posix_spawn_file_actions_adddup2 (&actions, child_fds_ [channel], fd);
138145 FUZZTEST_INTERNAL_CHECK (err == 0 ,
139146 " Cannot add dup2() action: " , strerror (err));
140- err = posix_spawn_file_actions_addclose (&actions, child_pipe_ [channel]);
147+ err = posix_spawn_file_actions_addclose (&actions, child_fds_ [channel]);
141148 FUZZTEST_INTERNAL_CHECK (err == 0 ,
142149 " Cannot add close() action: " , strerror (err));
143150 }
@@ -193,10 +200,10 @@ void SubProcess::ReadChildOutput(std::string* stdout_output,
193200 std::string* stderr_output) {
194201 // Set up poll()-ing the pipes.
195202 constexpr int fd_count = 2 ;
196- struct pollfd pfd[fd_count];
203+ struct pollfd pfd[fd_count + 1 ];
197204 std::string* out_str[fd_count];
198205 for (int channel : {kStdOutIdx , kStdErrIdx }) {
199- pfd[channel].fd = parent_pipe_ [channel];
206+ pfd[channel].fd = parent_fds_ [channel];
200207 pfd[channel].events = POLLIN;
201208 pfd[channel].revents = 0 ;
202209 out_str[channel] = channel == kStdOutIdx ? stdout_output : stderr_output;
@@ -247,7 +254,7 @@ int Wait(pid_t pid) {
247254// TODO(lszekeres): Consider optimizing this further by eliminating polling.
248255// Could potentially be done using pselect() to wait for SIGCHLD with a timeout.
249256// I.e., by setting all args to null, except timeout with a sigmask for SIGCHLD.
250- int WaitWithTimeout (pid_t pid, absl::Duration timeout) {
257+ int WaitWithTimeout (pid_t pid, int fds_to_shutdown[ 2 ], absl::Duration timeout) {
251258 int status;
252259 const absl::Time wait_until = absl::Now () + timeout;
253260 constexpr absl::Duration sleep_duration = absl::Milliseconds (100 );
@@ -259,17 +266,25 @@ int WaitWithTimeout(pid_t pid, absl::Duration timeout) {
259266 if (absl::Now () > wait_until) {
260267 FUZZTEST_INTERNAL_CHECK (kill (pid, SIGTERM) == 0 ,
261268 " Cannot kill(): " , strerror (errno));
262- return Wait (pid);
269+ status = Wait (pid);
270+ break ;
263271 } else {
264272 absl::SleepFor (sleep_duration);
265273 continue ;
266274 }
267275 } else if (ret == pid && (WIFEXITED (status) || WIFSIGNALED (status))) {
268- return status ;
276+ break ;
269277 } else {
270278 FUZZTEST_INTERNAL_CHECK (false , " wait() error: " , strerror (errno));
271279 }
272280 }
281+ FUZZTEST_INTERNAL_CHECK (
282+ shutdown (fds_to_shutdown[0 ], SHUT_RD) == 0 ,
283+ " Cannot shutdown fds_to_shutdown: " , fds_to_shutdown[0 ], strerror (errno));
284+ FUZZTEST_INTERNAL_CHECK (
285+ shutdown (fds_to_shutdown[1 ], SHUT_RD) == 0 ,
286+ " Cannot shutdown fds_to_shutdown: " , fds_to_shutdown[1 ], strerror (errno));
287+ return status;
273288}
274289
275290} // anonymous namespace
@@ -278,15 +293,17 @@ RunResults SubProcess::Run(
278293 const std::vector<std::string>& command_line,
279294 const absl::flat_hash_map<std::string, std::string>& environment,
280295 absl::Duration timeout) {
281- CreatePipes ();
296+ CreateCommunicationFds ();
282297 pid_t child_pid = StartChild (command_line, environment);
283- CloseChildPipes ();
284- std::future<int > status =
285- std::async (std::launch::async, &WaitWithTimeout, child_pid, timeout);
298+ CloseChildFds ();
299+ std::future<int > status = std::async (std::launch::async, &WaitWithTimeout,
300+ child_pid, parent_fds_ , timeout);
286301 std::string stdout_output, stderr_output;
287302 ReadChildOutput (&stdout_output, &stderr_output);
288- CloseParentPipes ();
289- return {TerminationStatus (status.get ()), stdout_output, stderr_output};
303+ RunResults result = {TerminationStatus (status.get ()), stdout_output,
304+ stderr_output};
305+ CloseParentFds ();
306+ return result;
290307}
291308
292309#endif // !defined(_MSC_VER) && !(defined(__ANDROID_MIN_SDK_VERSION__) &&
0 commit comments