Index: base/process/launch_win.cc |
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc |
index fa59f1ae90744469e397d3bd778cb8b1e98150c4..324eee7365aebfefaff619d44b9e64cecbb6aab4 100644 |
--- a/base/process/launch_win.cc |
+++ b/base/process/launch_win.cc |
@@ -46,9 +46,91 @@ namespace { |
// process goes away. |
const DWORD kProcessKilledExitCode = 1; |
+bool GetAppOutputInternal(const StringPiece16& cl, |
+ bool include_stderr, |
+ std::string* output) { |
+ HANDLE out_read = NULL; |
+ HANDLE out_write = NULL; |
+ |
+ SECURITY_ATTRIBUTES sa_attr; |
+ // Set the bInheritHandle flag so pipe handles are inherited. |
+ sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
+ sa_attr.bInheritHandle = TRUE; |
+ sa_attr.lpSecurityDescriptor = NULL; |
+ |
+ // Create the pipe for the child process's STDOUT. |
+ if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { |
+ NOTREACHED() << "Failed to create pipe"; |
+ return false; |
+ } |
+ |
+ // Ensure we don't leak the handles. |
+ win::ScopedHandle scoped_out_read(out_read); |
+ win::ScopedHandle scoped_out_write(out_write); |
+ |
+ // Ensure the read handles to the pipes are not inherited. |
+ if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { |
+ NOTREACHED() << "Failed to disabled pipe inheritance"; |
+ return false; |
+ } |
+ |
+ FilePath::StringType writable_command_line_string; |
+ writable_command_line_string.assign(cl.data(), cl.size()); |
+ |
+ STARTUPINFO start_info = {}; |
+ |
+ start_info.cb = sizeof(STARTUPINFO); |
+ start_info.hStdOutput = out_write; |
+ // Keep the normal stdin. |
+ start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
+ if (include_stderr) { |
+ start_info.hStdError = out_write; |
+ } else { |
+ start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
+ } |
+ start_info.dwFlags |= STARTF_USESTDHANDLES; |
+ |
+ // Create the child process. |
+ PROCESS_INFORMATION temp_process_info = {}; |
+ if (!CreateProcess(NULL, |
+ &writable_command_line_string[0], |
+ NULL, NULL, |
+ TRUE, // Handles are inherited. |
+ 0, NULL, NULL, &start_info, &temp_process_info)) { |
+ NOTREACHED() << "Failed to start process"; |
+ return false; |
+ } |
+ base::win::ScopedProcessInformation proc_info(temp_process_info); |
+ |
+ // Close our writing end of pipe now. Otherwise later read would not be able |
+ // to detect end of child's output. |
+ scoped_out_write.Close(); |
+ |
+ // Read output from the child process's pipe for STDOUT |
+ const int kBufferSize = 1024; |
+ char buffer[kBufferSize]; |
+ |
+ for (;;) { |
+ DWORD bytes_read = 0; |
+ BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); |
+ if (!success || bytes_read == 0) |
+ break; |
+ output->append(buffer, bytes_read); |
+ } |
+ |
+ // Let's wait for the process to finish. |
+ WaitForSingleObject(proc_info.process_handle(), INFINITE); |
+ |
+ int exit_code; |
+ base::TerminationStatus status = GetTerminationStatus( |
+ proc_info.process_handle(), &exit_code); |
+ return status != base::TERMINATION_STATUS_PROCESS_CRASHED && |
+ status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; |
+} |
+ |
} // namespace |
-void RouteStdioToConsole() { |
+void RouteStdioToConsole(bool create_console_if_not_found) { |
// Don't change anything if stdout or stderr already point to a |
// valid stream. |
// |
@@ -64,8 +146,22 @@ void RouteStdioToConsole() { |
// stdout/stderr on startup (before the handle IDs can be reused). |
// _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was |
// invalid. |
- if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) |
- return; |
+ if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) { |
+ // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013. |
+ // http://crbug.com/358267. Confirm that the underlying HANDLE is valid |
+ // before aborting. |
+ |
+ // This causes NaCl tests to hang on XP for reasons unclear, perhaps due |
+ // to not being able to inherit handles. Since it's only for debugging, |
+ // and redirecting still works, punt for now. |
+ if (base::win::GetVersion() < base::win::VERSION_VISTA) |
+ return; |
+ |
+ intptr_t stdout_handle = _get_osfhandle(_fileno(stdout)); |
+ intptr_t stderr_handle = _get_osfhandle(_fileno(stderr)); |
+ if (stdout_handle >= 0 || stderr_handle >= 0) |
+ return; |
+ } |
if (!AttachConsole(ATTACH_PARENT_PROCESS)) { |
unsigned int result = GetLastError(); |
@@ -76,10 +172,12 @@ void RouteStdioToConsole() { |
// parent process is invalid (eg: crashed). |
if (result == ERROR_GEN_FAILURE) |
return; |
- // Make a new console if attaching to parent fails with any other error. |
- // It should be ERROR_INVALID_HANDLE at this point, which means the browser |
- // was likely not started from a console. |
- AllocConsole(); |
+ if (create_console_if_not_found) { |
+ // Make a new console if attaching to parent fails with any other error. |
+ // It should be ERROR_INVALID_HANDLE at this point, which means the |
+ // browser was likely not started from a console. |
+ AllocConsole(); |
+ } |
} |
// Arbitrary byte count to use when buffering output lines. More |
@@ -274,76 +372,12 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) { |
return GetAppOutput(cl.GetCommandLineString(), output); |
} |
-bool GetAppOutput(const StringPiece16& cl, std::string* output) { |
- HANDLE out_read = NULL; |
- HANDLE out_write = NULL; |
- |
- SECURITY_ATTRIBUTES sa_attr; |
- // Set the bInheritHandle flag so pipe handles are inherited. |
- sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); |
- sa_attr.bInheritHandle = TRUE; |
- sa_attr.lpSecurityDescriptor = NULL; |
- |
- // Create the pipe for the child process's STDOUT. |
- if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { |
- NOTREACHED() << "Failed to create pipe"; |
- return false; |
- } |
- |
- // Ensure we don't leak the handles. |
- win::ScopedHandle scoped_out_read(out_read); |
- win::ScopedHandle scoped_out_write(out_write); |
- |
- // Ensure the read handle to the pipe for STDOUT is not inherited. |
- if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { |
- NOTREACHED() << "Failed to disabled pipe inheritance"; |
- return false; |
- } |
- |
- FilePath::StringType writable_command_line_string; |
- writable_command_line_string.assign(cl.data(), cl.size()); |
- |
- STARTUPINFO start_info = {}; |
- |
- start_info.cb = sizeof(STARTUPINFO); |
- start_info.hStdOutput = out_write; |
- // Keep the normal stdin and stderr. |
- start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
- start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
- start_info.dwFlags |= STARTF_USESTDHANDLES; |
- |
- // Create the child process. |
- PROCESS_INFORMATION temp_process_info = {}; |
- if (!CreateProcess(NULL, |
- &writable_command_line_string[0], |
- NULL, NULL, |
- TRUE, // Handles are inherited. |
- 0, NULL, NULL, &start_info, &temp_process_info)) { |
- NOTREACHED() << "Failed to start process"; |
- return false; |
- } |
- base::win::ScopedProcessInformation proc_info(temp_process_info); |
- |
- // Close our writing end of pipe now. Otherwise later read would not be able |
- // to detect end of child's output. |
- scoped_out_write.Close(); |
- |
- // Read output from the child process's pipe for STDOUT |
- const int kBufferSize = 1024; |
- char buffer[kBufferSize]; |
- |
- for (;;) { |
- DWORD bytes_read = 0; |
- BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); |
- if (!success || bytes_read == 0) |
- break; |
- output->append(buffer, bytes_read); |
- } |
- |
- // Let's wait for the process to finish. |
- WaitForSingleObject(proc_info.process_handle(), INFINITE); |
+bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { |
+ return GetAppOutputInternal(cl.GetCommandLineString(), true, output); |
+} |
- return true; |
+bool GetAppOutput(const StringPiece16& cl, std::string* output) { |
+ return GetAppOutputInternal(cl, false, output); |
} |
void RaiseProcessToHighPriority() { |