OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/process/launch.h" | 5 #include "base/process/launch.h" |
6 | 6 |
7 #include <dirent.h> | 7 #include <dirent.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <sched.h> | 10 #include <sched.h> |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 size_t fd_shuffle_size = 0; | 310 size_t fd_shuffle_size = 0; |
311 if (options.fds_to_remap) { | 311 if (options.fds_to_remap) { |
312 fd_shuffle_size = options.fds_to_remap->size(); | 312 fd_shuffle_size = options.fds_to_remap->size(); |
313 } | 313 } |
314 | 314 |
315 InjectiveMultimap fd_shuffle1; | 315 InjectiveMultimap fd_shuffle1; |
316 InjectiveMultimap fd_shuffle2; | 316 InjectiveMultimap fd_shuffle2; |
317 fd_shuffle1.reserve(fd_shuffle_size); | 317 fd_shuffle1.reserve(fd_shuffle_size); |
318 fd_shuffle2.reserve(fd_shuffle_size); | 318 fd_shuffle2.reserve(fd_shuffle_size); |
319 | 319 |
320 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); | 320 std::vector<char*> argv_cstr; |
321 for (size_t i = 0; i < argv.size(); i++) { | 321 argv_cstr.reserve(argv.size() + 1); |
322 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 322 for (const auto& arg : argv) |
323 } | 323 argv_cstr.push_back(const_cast<char*>(arg.c_str())); |
324 argv_cstr[argv.size()] = nullptr; | 324 argv_cstr.push_back(nullptr); |
325 | 325 |
326 std::unique_ptr<char* []> new_environ; | 326 std::unique_ptr<char* []> new_environ; |
327 char* const empty_environ = nullptr; | 327 char* const empty_environ = nullptr; |
328 char* const* old_environ = GetEnvironment(); | 328 char* const* old_environ = GetEnvironment(); |
329 if (options.clear_environ) | 329 if (options.clear_environ) |
330 old_environ = &empty_environ; | 330 old_environ = &empty_environ; |
331 if (!options.environ.empty()) | 331 if (!options.environ.empty()) |
332 new_environ = AlterEnvironment(old_environ, options.environ); | 332 new_environ = AlterEnvironment(old_environ, options.environ); |
333 | 333 |
334 sigset_t full_sigset; | 334 sigset_t full_sigset; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 RAW_CHECK(chdir(current_directory) == 0); | 499 RAW_CHECK(chdir(current_directory) == 0); |
500 } | 500 } |
501 | 501 |
502 if (options.pre_exec_delegate != nullptr) { | 502 if (options.pre_exec_delegate != nullptr) { |
503 options.pre_exec_delegate->RunAsyncSafe(); | 503 options.pre_exec_delegate->RunAsyncSafe(); |
504 } | 504 } |
505 | 505 |
506 const char* executable_path = !options.real_path.empty() ? | 506 const char* executable_path = !options.real_path.empty() ? |
507 options.real_path.value().c_str() : argv_cstr[0]; | 507 options.real_path.value().c_str() : argv_cstr[0]; |
508 | 508 |
509 execvp(executable_path, argv_cstr.get()); | 509 execvp(executable_path, argv_cstr.data()); |
510 | 510 |
511 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); | 511 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); |
512 RAW_LOG(ERROR, argv_cstr[0]); | 512 RAW_LOG(ERROR, argv_cstr[0]); |
513 _exit(127); | 513 _exit(127); |
514 } else { | 514 } else { |
515 // Parent process | 515 // Parent process |
516 if (options.wait) { | 516 if (options.wait) { |
517 // While this isn't strictly disk IO, waiting for another process to | 517 // While this isn't strictly disk IO, waiting for another process to |
518 // finish is the sort of thing ThreadRestrictions is trying to prevent. | 518 // finish is the sort of thing ThreadRestrictions is trying to prevent. |
519 base::ThreadRestrictions::AssertIOAllowed(); | 519 base::ThreadRestrictions::AssertIOAllowed(); |
(...skipping 26 matching lines...) Expand all Loading... |
546 bool include_stderr, | 546 bool include_stderr, |
547 std::string* output, | 547 std::string* output, |
548 bool do_search_path, | 548 bool do_search_path, |
549 int* exit_code) { | 549 int* exit_code) { |
550 // Doing a blocking wait for another command to finish counts as IO. | 550 // Doing a blocking wait for another command to finish counts as IO. |
551 base::ThreadRestrictions::AssertIOAllowed(); | 551 base::ThreadRestrictions::AssertIOAllowed(); |
552 // exit_code must be supplied so calling function can determine success. | 552 // exit_code must be supplied so calling function can determine success. |
553 DCHECK(exit_code); | 553 DCHECK(exit_code); |
554 *exit_code = EXIT_FAILURE; | 554 *exit_code = EXIT_FAILURE; |
555 | 555 |
556 int pipe_fd[2]; | 556 // Declare and call reserve() here before calling fork() because the child |
557 pid_t pid; | 557 // process cannot allocate memory. |
558 InjectiveMultimap fd_shuffle1, fd_shuffle2; | 558 std::vector<char*> argv_cstr; |
559 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); | 559 argv_cstr.reserve(argv.size() + 1); |
560 | 560 InjectiveMultimap fd_shuffle1; |
| 561 InjectiveMultimap fd_shuffle2; |
561 fd_shuffle1.reserve(3); | 562 fd_shuffle1.reserve(3); |
562 fd_shuffle2.reserve(3); | 563 fd_shuffle2.reserve(3); |
563 | 564 |
564 // Either |do_search_path| should be false or |envp| should be null, but not | 565 // Either |do_search_path| should be false or |envp| should be null, but not |
565 // both. | 566 // both. |
566 DCHECK(!do_search_path ^ !envp); | 567 DCHECK(!do_search_path ^ !envp); |
567 | 568 |
| 569 int pipe_fd[2]; |
568 if (pipe(pipe_fd) < 0) | 570 if (pipe(pipe_fd) < 0) |
569 return false; | 571 return false; |
570 | 572 |
571 switch (pid = fork()) { | 573 pid_t pid = fork(); |
572 case -1: // error | 574 switch (pid) { |
| 575 case -1: { |
| 576 // error |
573 close(pipe_fd[0]); | 577 close(pipe_fd[0]); |
574 close(pipe_fd[1]); | 578 close(pipe_fd[1]); |
575 return false; | 579 return false; |
576 case 0: // child | 580 } |
577 { | 581 case 0: { |
578 // DANGER: no calls to malloc or locks are allowed from now on: | 582 // child |
579 // http://crbug.com/36678 | 583 // |
| 584 // DANGER: no calls to malloc or locks are allowed from now on: |
| 585 // http://crbug.com/36678 |
580 | 586 |
581 #if defined(OS_MACOSX) | 587 #if defined(OS_MACOSX) |
582 RestoreDefaultExceptionHandler(); | 588 RestoreDefaultExceptionHandler(); |
583 #endif | 589 #endif |
584 | 590 |
585 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 591 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
586 // you call _exit() instead of exit(). This is because _exit() does not | 592 // you call _exit() instead of exit(). This is because _exit() does not |
587 // call any previously-registered (in the parent) exit handlers, which | 593 // call any previously-registered (in the parent) exit handlers, which |
588 // might do things like block waiting for threads that don't even exist | 594 // might do things like block waiting for threads that don't even exist |
589 // in the child. | 595 // in the child. |
590 int dev_null = open("/dev/null", O_WRONLY); | 596 int dev_null = open("/dev/null", O_WRONLY); |
591 if (dev_null < 0) | 597 if (dev_null < 0) |
592 _exit(127); | 598 _exit(127); |
593 | 599 |
594 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); | 600 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); |
595 fd_shuffle1.push_back(InjectionArc( | 601 fd_shuffle1.push_back(InjectionArc(include_stderr ? pipe_fd[1] : dev_null, |
596 include_stderr ? pipe_fd[1] : dev_null, | 602 STDERR_FILENO, true)); |
597 STDERR_FILENO, true)); | 603 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); |
598 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); | 604 // Adding another element here? Remeber to increase the argument to |
599 // Adding another element here? Remeber to increase the argument to | 605 // reserve(), above. |
600 // reserve(), above. | |
601 | 606 |
602 for (size_t i = 0; i < fd_shuffle1.size(); ++i) | 607 for (size_t i = 0; i < fd_shuffle1.size(); ++i) |
603 fd_shuffle2.push_back(fd_shuffle1[i]); | 608 fd_shuffle2.push_back(fd_shuffle1[i]); |
604 | 609 |
605 if (!ShuffleFileDescriptors(&fd_shuffle1)) | 610 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
606 _exit(127); | 611 _exit(127); |
607 | 612 |
608 CloseSuperfluousFds(fd_shuffle2); | 613 CloseSuperfluousFds(fd_shuffle2); |
609 | 614 |
610 for (size_t i = 0; i < argv.size(); i++) | 615 for (const auto& arg : argv) |
611 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 616 argv_cstr.push_back(const_cast<char*>(arg.c_str())); |
612 argv_cstr[argv.size()] = nullptr; | 617 argv_cstr.push_back(nullptr); |
613 if (do_search_path) | 618 |
614 execvp(argv_cstr[0], argv_cstr.get()); | 619 if (do_search_path) |
615 else | 620 execvp(argv_cstr[0], argv_cstr.data()); |
616 execve(argv_cstr[0], argv_cstr.get(), envp); | 621 else |
617 _exit(127); | 622 execve(argv_cstr[0], argv_cstr.data(), envp); |
| 623 _exit(127); |
| 624 } |
| 625 default: { |
| 626 // parent |
| 627 // |
| 628 // Close our writing end of pipe now. Otherwise later read would not |
| 629 // be able to detect end of child's output (in theory we could still |
| 630 // write to the pipe). |
| 631 close(pipe_fd[1]); |
| 632 |
| 633 output->clear(); |
| 634 |
| 635 while (true) { |
| 636 char buffer[256]; |
| 637 ssize_t bytes_read = |
| 638 HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); |
| 639 if (bytes_read <= 0) |
| 640 break; |
| 641 output->append(buffer, bytes_read); |
618 } | 642 } |
619 default: // parent | 643 close(pipe_fd[0]); |
620 { | |
621 // Close our writing end of pipe now. Otherwise later read would not | |
622 // be able to detect end of child's output (in theory we could still | |
623 // write to the pipe). | |
624 close(pipe_fd[1]); | |
625 | 644 |
626 output->clear(); | 645 // Always wait for exit code (even if we know we'll declare |
627 | 646 // GOT_MAX_OUTPUT). |
628 while (true) { | 647 Process process(pid); |
629 char buffer[256]; | 648 return process.WaitForExit(exit_code); |
630 ssize_t bytes_read = | 649 } |
631 HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); | |
632 if (bytes_read <= 0) | |
633 break; | |
634 output->append(buffer, bytes_read); | |
635 } | |
636 close(pipe_fd[0]); | |
637 | |
638 // Always wait for exit code (even if we know we'll declare | |
639 // GOT_MAX_OUTPUT). | |
640 Process process(pid); | |
641 return process.WaitForExit(exit_code); | |
642 } | |
643 } | 650 } |
644 } | 651 } |
645 | 652 |
646 bool GetAppOutput(const CommandLine& cl, std::string* output) { | 653 bool GetAppOutput(const CommandLine& cl, std::string* output) { |
647 return GetAppOutput(cl.argv(), output); | 654 return GetAppOutput(cl.argv(), output); |
648 } | 655 } |
649 | 656 |
650 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { | 657 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { |
651 // Run |execve()| with the current environment. | 658 // Run |execve()| with the current environment. |
652 int exit_code; | 659 int exit_code; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 jmp_buf env; | 773 jmp_buf env; |
767 if (setjmp(env) == 0) { | 774 if (setjmp(env) == 0) { |
768 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); | 775 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); |
769 } | 776 } |
770 | 777 |
771 return 0; | 778 return 0; |
772 } | 779 } |
773 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) | 780 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) |
774 | 781 |
775 } // namespace base | 782 } // namespace base |
OLD | NEW |