| 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() {
|
|
|