1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 
33 #include <google/protobuf/compiler/subprocess.h>
34 
35 #include <algorithm>
36 #include <iostream>
37 
38 #ifndef _WIN32
39 #include <errno.h>
40 #include <sys/select.h>
41 #include <sys/wait.h>
42 #include <signal.h>
43 #endif
44 
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/message.h>
47 #include <google/protobuf/stubs/substitute.h>
48 
49 namespace google {
50 namespace protobuf {
51 namespace compiler {
52 
53 #ifdef _WIN32
54 
CloseHandleOrDie(HANDLE handle)55 static void CloseHandleOrDie(HANDLE handle) {
56   if (!CloseHandle(handle)) {
57     GOOGLE_LOG(FATAL) << "CloseHandle: "
58                       << Subprocess::Win32ErrorMessage(GetLastError());
59   }
60 }
61 
Subprocess()62 Subprocess::Subprocess()
63     : process_start_error_(ERROR_SUCCESS),
64       child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
65 
~Subprocess()66 Subprocess::~Subprocess() {
67   if (child_stdin_ != NULL) {
68     CloseHandleOrDie(child_stdin_);
69   }
70   if (child_stdout_ != NULL) {
71     CloseHandleOrDie(child_stdout_);
72   }
73 }
74 
Start(const string & program,SearchMode search_mode)75 void Subprocess::Start(const string& program, SearchMode search_mode) {
76   // Create the pipes.
77   HANDLE stdin_pipe_read;
78   HANDLE stdin_pipe_write;
79   HANDLE stdout_pipe_read;
80   HANDLE stdout_pipe_write;
81 
82   if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
83     GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
84   }
85   if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
86     GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
87   }
88 
89   // Make child side of the pipes inheritable.
90   if (!SetHandleInformation(stdin_pipe_read,
91                             HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
92     GOOGLE_LOG(FATAL) << "SetHandleInformation: "
93                       << Win32ErrorMessage(GetLastError());
94   }
95   if (!SetHandleInformation(stdout_pipe_write,
96                             HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
97     GOOGLE_LOG(FATAL) << "SetHandleInformation: "
98                       << Win32ErrorMessage(GetLastError());
99   }
100 
101   // Setup STARTUPINFO to redirect handles.
102   STARTUPINFOA startup_info;
103   ZeroMemory(&startup_info, sizeof(startup_info));
104   startup_info.cb = sizeof(startup_info);
105   startup_info.dwFlags = STARTF_USESTDHANDLES;
106   startup_info.hStdInput = stdin_pipe_read;
107   startup_info.hStdOutput = stdout_pipe_write;
108   startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
109 
110   if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
111     GOOGLE_LOG(FATAL) << "GetStdHandle: "
112                       << Win32ErrorMessage(GetLastError());
113   }
114 
115   // CreateProcess() mutates its second parameter.  WTF?
116   char* name_copy = strdup(program.c_str());
117 
118   // Create the process.
119   PROCESS_INFORMATION process_info;
120 
121   if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
122                      (search_mode == SEARCH_PATH) ? name_copy : NULL,
123                      NULL,  // process security attributes
124                      NULL,  // thread security attributes
125                      TRUE,  // inherit handles?
126                      0,     // obscure creation flags
127                      NULL,  // environment (inherit from parent)
128                      NULL,  // current directory (inherit from parent)
129                      &startup_info,
130                      &process_info)) {
131     child_handle_ = process_info.hProcess;
132     CloseHandleOrDie(process_info.hThread);
133     child_stdin_ = stdin_pipe_write;
134     child_stdout_ = stdout_pipe_read;
135   } else {
136     process_start_error_ = GetLastError();
137     CloseHandleOrDie(stdin_pipe_write);
138     CloseHandleOrDie(stdout_pipe_read);
139   }
140 
141   CloseHandleOrDie(stdin_pipe_read);
142   CloseHandleOrDie(stdout_pipe_write);
143   free(name_copy);
144 }
145 
Communicate(const Message & input,Message * output,string * error)146 bool Subprocess::Communicate(const Message& input, Message* output,
147                              string* error) {
148   if (process_start_error_ != ERROR_SUCCESS) {
149     *error = Win32ErrorMessage(process_start_error_);
150     return false;
151   }
152 
153   GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";
154 
155   string input_data = input.SerializeAsString();
156   string output_data;
157 
158   int input_pos = 0;
159 
160   while (child_stdout_ != NULL) {
161     HANDLE handles[2];
162     int handle_count = 0;
163 
164     if (child_stdin_ != NULL) {
165       handles[handle_count++] = child_stdin_;
166     }
167     if (child_stdout_ != NULL) {
168       handles[handle_count++] = child_stdout_;
169     }
170 
171     DWORD wait_result =
172         WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
173 
174     HANDLE signaled_handle;
175     if (wait_result >= WAIT_OBJECT_0 &&
176         wait_result < WAIT_OBJECT_0 + handle_count) {
177       signaled_handle = handles[wait_result - WAIT_OBJECT_0];
178     } else if (wait_result == WAIT_FAILED) {
179       GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
180                         << Win32ErrorMessage(GetLastError());
181     } else {
182       GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
183                         << wait_result;
184     }
185 
186     if (signaled_handle == child_stdin_) {
187       DWORD n;
188       if (!WriteFile(child_stdin_,
189                      input_data.data() + input_pos,
190                      input_data.size() - input_pos,
191                      &n, NULL)) {
192         // Child closed pipe.  Presumably it will report an error later.
193         // Pretend we're done for now.
194         input_pos = input_data.size();
195       } else {
196         input_pos += n;
197       }
198 
199       if (input_pos == input_data.size()) {
200         // We're done writing.  Close.
201         CloseHandleOrDie(child_stdin_);
202         child_stdin_ = NULL;
203       }
204     } else if (signaled_handle == child_stdout_) {
205       char buffer[4096];
206       DWORD n;
207 
208       if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
209         // We're done reading.  Close.
210         CloseHandleOrDie(child_stdout_);
211         child_stdout_ = NULL;
212       } else {
213         output_data.append(buffer, n);
214       }
215     }
216   }
217 
218   if (child_stdin_ != NULL) {
219     // Child did not finish reading input before it closed the output.
220     // Presumably it exited with an error.
221     CloseHandleOrDie(child_stdin_);
222     child_stdin_ = NULL;
223   }
224 
225   DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
226 
227   if (wait_result == WAIT_FAILED) {
228     GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
229                       << Win32ErrorMessage(GetLastError());
230   } else if (wait_result != WAIT_OBJECT_0) {
231     GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
232                       << wait_result;
233   }
234 
235   DWORD exit_code;
236   if (!GetExitCodeProcess(child_handle_, &exit_code)) {
237     GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
238                       << Win32ErrorMessage(GetLastError());
239   }
240 
241   CloseHandleOrDie(child_handle_);
242   child_handle_ = NULL;
243 
244   if (exit_code != 0) {
245     *error = strings::Substitute(
246         "Plugin failed with status code $0.", exit_code);
247     return false;
248   }
249 
250   if (!output->ParseFromString(output_data)) {
251     *error = "Plugin output is unparseable: " + CEscape(output_data);
252     return false;
253   }
254 
255   return true;
256 }
257 
Win32ErrorMessage(DWORD error_code)258 string Subprocess::Win32ErrorMessage(DWORD error_code) {
259   char* message;
260 
261   // WTF?
262   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
263                 FORMAT_MESSAGE_FROM_SYSTEM |
264                 FORMAT_MESSAGE_IGNORE_INSERTS,
265                 NULL, error_code, 0,
266                 (LPTSTR)&message,  // NOT A BUG!
267                 0, NULL);
268 
269   string result = message;
270   LocalFree(message);
271   return result;
272 }
273 
274 // ===================================================================
275 
276 #else  // _WIN32
277 
278 Subprocess::Subprocess()
279     : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
280 
281 Subprocess::~Subprocess() {
282   if (child_stdin_ != -1) {
283     close(child_stdin_);
284   }
285   if (child_stdout_ != -1) {
286     close(child_stdout_);
287   }
288 }
289 
290 void Subprocess::Start(const string& program, SearchMode search_mode) {
291   // Note that we assume that there are no other threads, thus we don't have to
292   // do crazy stuff like using socket pairs or avoiding libc locks.
293 
294   // [0] is read end, [1] is write end.
295   int stdin_pipe[2];
296   int stdout_pipe[2];
297 
298   GOOGLE_CHECK(pipe(stdin_pipe) != -1);
299   GOOGLE_CHECK(pipe(stdout_pipe) != -1);
300 
301   char* argv[2] = { strdup(program.c_str()), NULL };
302 
303   child_pid_ = fork();
304   if (child_pid_ == -1) {
305     GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
306   } else if (child_pid_ == 0) {
307     // We are the child.
308     dup2(stdin_pipe[0], STDIN_FILENO);
309     dup2(stdout_pipe[1], STDOUT_FILENO);
310 
311     close(stdin_pipe[0]);
312     close(stdin_pipe[1]);
313     close(stdout_pipe[0]);
314     close(stdout_pipe[1]);
315 
316     switch (search_mode) {
317       case SEARCH_PATH:
318         execvp(argv[0], argv);
319         break;
320       case EXACT_NAME:
321         execv(argv[0], argv);
322         break;
323     }
324 
325     // Write directly to STDERR_FILENO to avoid stdio code paths that may do
326     // stuff that is unsafe here.
327     int ignored;
328     ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
329     const char* message = ": program not found or is not executable\n";
330     ignored = write(STDERR_FILENO, message, strlen(message));
331     (void) ignored;
332 
333     // Must use _exit() rather than exit() to avoid flushing output buffers
334     // that will also be flushed by the parent.
335     _exit(1);
336   } else {
337     free(argv[0]);
338 
339     close(stdin_pipe[0]);
340     close(stdout_pipe[1]);
341 
342     child_stdin_ = stdin_pipe[1];
343     child_stdout_ = stdout_pipe[0];
344   }
345 }
346 
347 bool Subprocess::Communicate(const Message& input, Message* output,
348                              string* error) {
349 
350   GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";
351 
352   // The "sighandler_t" typedef is GNU-specific, so define our own.
353   typedef void SignalHandler(int);
354 
355   // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
356   SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
357 
358   string input_data = input.SerializeAsString();
359   string output_data;
360 
361   int input_pos = 0;
362   int max_fd = max(child_stdin_, child_stdout_);
363 
364   while (child_stdout_ != -1) {
365     fd_set read_fds;
366     fd_set write_fds;
367     FD_ZERO(&read_fds);
368     FD_ZERO(&write_fds);
369     if (child_stdout_ != -1) {
370       FD_SET(child_stdout_, &read_fds);
371     }
372     if (child_stdin_ != -1) {
373       FD_SET(child_stdin_, &write_fds);
374     }
375 
376     if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
377       if (errno == EINTR) {
378         // Interrupted by signal.  Try again.
379         continue;
380       } else {
381         GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
382       }
383     }
384 
385     if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
386       int n = write(child_stdin_, input_data.data() + input_pos,
387                                   input_data.size() - input_pos);
388       if (n < 0) {
389         // Child closed pipe.  Presumably it will report an error later.
390         // Pretend we're done for now.
391         input_pos = input_data.size();
392       } else {
393         input_pos += n;
394       }
395 
396       if (input_pos == input_data.size()) {
397         // We're done writing.  Close.
398         close(child_stdin_);
399         child_stdin_ = -1;
400       }
401     }
402 
403     if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
404       char buffer[4096];
405       int n = read(child_stdout_, buffer, sizeof(buffer));
406 
407       if (n > 0) {
408         output_data.append(buffer, n);
409       } else {
410         // We're done reading.  Close.
411         close(child_stdout_);
412         child_stdout_ = -1;
413       }
414     }
415   }
416 
417   if (child_stdin_ != -1) {
418     // Child did not finish reading input before it closed the output.
419     // Presumably it exited with an error.
420     close(child_stdin_);
421     child_stdin_ = -1;
422   }
423 
424   int status;
425   while (waitpid(child_pid_, &status, 0) == -1) {
426     if (errno != EINTR) {
427       GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
428     }
429   }
430 
431   // Restore SIGPIPE handling.
432   signal(SIGPIPE, old_pipe_handler);
433 
434   if (WIFEXITED(status)) {
435     if (WEXITSTATUS(status) != 0) {
436       int error_code = WEXITSTATUS(status);
437       *error = strings::Substitute(
438           "Plugin failed with status code $0.", error_code);
439       return false;
440     }
441   } else if (WIFSIGNALED(status)) {
442     int signal = WTERMSIG(status);
443     *error = strings::Substitute(
444         "Plugin killed by signal $0.", signal);
445     return false;
446   } else {
447     *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
448     return false;
449   }
450 
451   if (!output->ParseFromString(output_data)) {
452     *error = "Plugin output is unparseable: " + CEscape(output_data);
453     return false;
454   }
455 
456   return true;
457 }
458 
459 #endif  // !_WIN32
460 
461 }  // namespace compiler
462 }  // namespace protobuf
463 }  // namespace google
464