| Index: base/process/launch_posix.cc
|
| diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
|
| index 7550a36f521440e0189603846d5d10f1bd4ed413..b841dee3276eae3cfa9ee7b18c6bf86b14932e3a 100644
|
| --- a/base/process/launch_posix.cc
|
| +++ b/base/process/launch_posix.cc
|
| @@ -317,11 +317,11 @@ Process LaunchProcess(const std::vector<std::string>& argv,
|
| fd_shuffle1.reserve(fd_shuffle_size);
|
| fd_shuffle2.reserve(fd_shuffle_size);
|
|
|
| - std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]);
|
| - for (size_t i = 0; i < argv.size(); i++) {
|
| - argv_cstr[i] = const_cast<char*>(argv[i].c_str());
|
| - }
|
| - argv_cstr[argv.size()] = nullptr;
|
| + std::vector<char*> argv_cstr;
|
| + argv_cstr.reserve(argv.size() + 1);
|
| + for (const auto& arg : argv)
|
| + argv_cstr.push_back(const_cast<char*>(arg.c_str()));
|
| + argv_cstr.push_back(nullptr);
|
|
|
| std::unique_ptr<char* []> new_environ;
|
| char* const empty_environ = nullptr;
|
| @@ -506,7 +506,7 @@ Process LaunchProcess(const std::vector<std::string>& argv,
|
| const char* executable_path = !options.real_path.empty() ?
|
| options.real_path.value().c_str() : argv_cstr[0];
|
|
|
| - execvp(executable_path, argv_cstr.get());
|
| + execvp(executable_path, argv_cstr.data());
|
|
|
| RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
|
| RAW_LOG(ERROR, argv_cstr[0]);
|
| @@ -553,11 +553,12 @@ static bool GetAppOutputInternal(
|
| DCHECK(exit_code);
|
| *exit_code = EXIT_FAILURE;
|
|
|
| - int pipe_fd[2];
|
| - pid_t pid;
|
| - InjectiveMultimap fd_shuffle1, fd_shuffle2;
|
| - std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]);
|
| -
|
| + // Declare and call reserve() here before calling fork() because the child
|
| + // process cannot allocate memory.
|
| + std::vector<char*> argv_cstr;
|
| + argv_cstr.reserve(argv.size() + 1);
|
| + InjectiveMultimap fd_shuffle1;
|
| + InjectiveMultimap fd_shuffle2;
|
| fd_shuffle1.reserve(3);
|
| fd_shuffle2.reserve(3);
|
|
|
| @@ -565,81 +566,87 @@ static bool GetAppOutputInternal(
|
| // both.
|
| DCHECK(!do_search_path ^ !envp);
|
|
|
| + int pipe_fd[2];
|
| if (pipe(pipe_fd) < 0)
|
| return false;
|
|
|
| - switch (pid = fork()) {
|
| - case -1: // error
|
| + pid_t pid = fork();
|
| + switch (pid) {
|
| + case -1: {
|
| + // error
|
| close(pipe_fd[0]);
|
| close(pipe_fd[1]);
|
| return false;
|
| - case 0: // child
|
| - {
|
| - // DANGER: no calls to malloc or locks are allowed from now on:
|
| - // http://crbug.com/36678
|
| + }
|
| + case 0: {
|
| + // child
|
| + //
|
| + // DANGER: no calls to malloc or locks are allowed from now on:
|
| + // http://crbug.com/36678
|
|
|
| #if defined(OS_MACOSX)
|
| - RestoreDefaultExceptionHandler();
|
| + RestoreDefaultExceptionHandler();
|
| #endif
|
|
|
| - // Obscure fork() rule: in the child, if you don't end up doing exec*(),
|
| - // you call _exit() instead of exit(). This is because _exit() does not
|
| - // call any previously-registered (in the parent) exit handlers, which
|
| - // might do things like block waiting for threads that don't even exist
|
| - // in the child.
|
| - int dev_null = open("/dev/null", O_WRONLY);
|
| - if (dev_null < 0)
|
| - _exit(127);
|
| -
|
| - fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
|
| - fd_shuffle1.push_back(InjectionArc(
|
| - include_stderr ? pipe_fd[1] : dev_null,
|
| - STDERR_FILENO, true));
|
| - fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
|
| - // Adding another element here? Remeber to increase the argument to
|
| - // reserve(), above.
|
| -
|
| - for (size_t i = 0; i < fd_shuffle1.size(); ++i)
|
| - fd_shuffle2.push_back(fd_shuffle1[i]);
|
| -
|
| - if (!ShuffleFileDescriptors(&fd_shuffle1))
|
| - _exit(127);
|
| -
|
| - CloseSuperfluousFds(fd_shuffle2);
|
| -
|
| - for (size_t i = 0; i < argv.size(); i++)
|
| - argv_cstr[i] = const_cast<char*>(argv[i].c_str());
|
| - argv_cstr[argv.size()] = nullptr;
|
| - if (do_search_path)
|
| - execvp(argv_cstr[0], argv_cstr.get());
|
| - else
|
| - execve(argv_cstr[0], argv_cstr.get(), envp);
|
| + // Obscure fork() rule: in the child, if you don't end up doing exec*(),
|
| + // you call _exit() instead of exit(). This is because _exit() does not
|
| + // call any previously-registered (in the parent) exit handlers, which
|
| + // might do things like block waiting for threads that don't even exist
|
| + // in the child.
|
| + int dev_null = open("/dev/null", O_WRONLY);
|
| + if (dev_null < 0)
|
| _exit(127);
|
| - }
|
| - default: // parent
|
| - {
|
| - // Close our writing end of pipe now. Otherwise later read would not
|
| - // be able to detect end of child's output (in theory we could still
|
| - // write to the pipe).
|
| - close(pipe_fd[1]);
|
| -
|
| - output->clear();
|
| -
|
| - while (true) {
|
| - char buffer[256];
|
| - ssize_t bytes_read =
|
| - HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer)));
|
| - if (bytes_read <= 0)
|
| - break;
|
| - output->append(buffer, bytes_read);
|
| - }
|
| - close(pipe_fd[0]);
|
|
|
| - // Always wait for exit code (even if we know we'll declare
|
| - // GOT_MAX_OUTPUT).
|
| - Process process(pid);
|
| - return process.WaitForExit(exit_code);
|
| + fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
|
| + fd_shuffle1.push_back(InjectionArc(include_stderr ? pipe_fd[1] : dev_null,
|
| + STDERR_FILENO, true));
|
| + fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
|
| + // Adding another element here? Remeber to increase the argument to
|
| + // reserve(), above.
|
| +
|
| + for (size_t i = 0; i < fd_shuffle1.size(); ++i)
|
| + fd_shuffle2.push_back(fd_shuffle1[i]);
|
| +
|
| + if (!ShuffleFileDescriptors(&fd_shuffle1))
|
| + _exit(127);
|
| +
|
| + CloseSuperfluousFds(fd_shuffle2);
|
| +
|
| + for (const auto& arg : argv)
|
| + argv_cstr.push_back(const_cast<char*>(arg.c_str()));
|
| + argv_cstr.push_back(nullptr);
|
| +
|
| + if (do_search_path)
|
| + execvp(argv_cstr[0], argv_cstr.data());
|
| + else
|
| + execve(argv_cstr[0], argv_cstr.data(), envp);
|
| + _exit(127);
|
| + }
|
| + default: {
|
| + // parent
|
| + //
|
| + // Close our writing end of pipe now. Otherwise later read would not
|
| + // be able to detect end of child's output (in theory we could still
|
| + // write to the pipe).
|
| + close(pipe_fd[1]);
|
| +
|
| + output->clear();
|
| +
|
| + while (true) {
|
| + char buffer[256];
|
| + ssize_t bytes_read =
|
| + HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer)));
|
| + if (bytes_read <= 0)
|
| + break;
|
| + output->append(buffer, bytes_read);
|
| }
|
| + close(pipe_fd[0]);
|
| +
|
| + // Always wait for exit code (even if we know we'll declare
|
| + // GOT_MAX_OUTPUT).
|
| + Process process(pid);
|
| + return process.WaitForExit(exit_code);
|
| + }
|
| }
|
| }
|
|
|
|
|