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