Chromium Code Reviews| 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 <signal.h> | 10 #include <signal.h> |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 // Set the process's "environment" (i.e. the thing that setenv/getenv | 70 // Set the process's "environment" (i.e. the thing that setenv/getenv |
| 71 // work with). | 71 // work with). |
| 72 void SetEnvironment(char** env) { | 72 void SetEnvironment(char** env) { |
| 73 #if defined(OS_MACOSX) | 73 #if defined(OS_MACOSX) |
| 74 *_NSGetEnviron() = env; | 74 *_NSGetEnviron() = env; |
| 75 #else | 75 #else |
| 76 environ = env; | 76 environ = env; |
| 77 #endif | 77 #endif |
| 78 } | 78 } |
| 79 | 79 |
| 80 // Set the calling thread's signal mask to *new_set, and set *old_set | |
| 81 // to the previous signal mask. Returns true if successful. | |
| 82 bool SetSignalMask(const sigset_t *new_set, sigset_t *old_set) { | |
| 83 int error; | |
| 84 #if defined(OS_ANDROID) | |
| 85 // POSIX says pthread_sigmask() must be used in multi-threaded processes, | |
| 86 // but Android's pthread_sigmask() was broken until 4.1: | |
| 87 // https://code.google.com/p/android/issues/detail?id=15337 | |
| 88 // http://stackoverflow.com/questions/13777109/pthread-sigmask-on-android-not- working | |
| 89 error = sigprocmask(SIG_SETMASK, new_set, old_set); | |
| 90 #else | |
| 91 error = pthread_sigmask(SIG_SETMASK, new_set, old_set); | |
| 92 if (error != 0) { | |
| 93 errno = error; | |
| 94 } | |
| 95 #endif | |
| 96 if (error != 0) { | |
| 97 DPLOG(ERROR) << "SetSignalMask failed"; | |
| 98 return false; | |
| 99 } | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 80 #if !defined(OS_LINUX) || \ | 103 #if !defined(OS_LINUX) || \ |
| 81 (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) | 104 (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) |
| 82 void ResetChildSignalHandlersToDefaults() { | 105 void ResetChildSignalHandlersToDefaults() { |
| 83 // The previous signal handlers are likely to be meaningless in the child's | 106 // The previous signal handlers are likely to be meaningless in the child's |
| 84 // context so we reset them to the defaults for now. http://crbug.com/44953 | 107 // context so we reset them to the defaults for now. http://crbug.com/44953 |
| 85 // These signal handlers are set up at least in browser_main_posix.cc: | 108 // These signal handlers are set up at least in browser_main_posix.cc: |
| 86 // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: | 109 // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: |
| 87 // EnableInProcessStackDumping. | 110 // EnableInProcessStackDumping. |
| 88 signal(SIGHUP, SIG_DFL); | 111 signal(SIGHUP, SIG_DFL); |
| 89 signal(SIGINT, SIG_DFL); | 112 signal(SIGINT, SIG_DFL); |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 InjectiveMultimap fd_shuffle1; | 410 InjectiveMultimap fd_shuffle1; |
| 388 InjectiveMultimap fd_shuffle2; | 411 InjectiveMultimap fd_shuffle2; |
| 389 fd_shuffle1.reserve(fd_shuffle_size); | 412 fd_shuffle1.reserve(fd_shuffle_size); |
| 390 fd_shuffle2.reserve(fd_shuffle_size); | 413 fd_shuffle2.reserve(fd_shuffle_size); |
| 391 | 414 |
| 392 scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]); | 415 scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]); |
| 393 scoped_ptr<char*[]> new_environ; | 416 scoped_ptr<char*[]> new_environ; |
| 394 if (options.environ) | 417 if (options.environ) |
| 395 new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment())); | 418 new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment())); |
| 396 | 419 |
| 420 sigset_t full_sigset; | |
| 421 sigfillset(&full_sigset); | |
| 422 sigset_t old_sigset; | |
| 423 if (!SetSignalMask(&full_sigset, &old_sigset)) { | |
| 424 return false; | |
| 425 } | |
| 426 | |
| 397 pid_t pid; | 427 pid_t pid; |
| 398 #if defined(OS_LINUX) | 428 #if defined(OS_LINUX) |
| 399 if (options.clone_flags) { | 429 if (options.clone_flags) { |
| 430 CHECK_EQ(0, options.clone_flags & (CLONE_THREAD | CLONE_VM)); | |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
RAW_CHECK
mdempsky_google
2013/08/02 18:45:00
Done.
| |
| 400 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); | 431 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); |
| 401 } else | 432 } else |
| 402 #endif | 433 #endif |
| 403 { | 434 { |
| 404 pid = fork(); | 435 pid = fork(); |
| 405 } | 436 } |
| 406 | 437 |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
// Always restore the signal mask in the parent.
mdempsky_google
2013/08/02 18:45:00
Done.
| |
| 438 if (pid != 0) { | |
| 439 if (!SetSignalMask(&old_sigset, NULL)) { | |
| 440 NOTREACHED(); | |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
RAW_CHECK
mdempsky_google
2013/08/02 16:12:51
Is RAW_CHECK(x) guaranteed to always evaluate x?
mdempsky_google
2013/08/02 18:45:00
I moved the RAW_CHECK()s directly into SetSignalMa
| |
| 441 } | |
| 442 } | |
| 443 | |
| 407 if (pid < 0) { | 444 if (pid < 0) { |
| 408 DPLOG(ERROR) << "fork"; | 445 DPLOG(ERROR) << "fork"; |
| 409 return false; | 446 return false; |
| 410 } else if (pid == 0) { | 447 } else if (pid == 0) { |
| 411 // Child process | 448 // Child process |
| 412 | 449 |
| 413 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), | 450 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), |
| 414 // you call _exit() instead of exit(). This is because _exit() does not | 451 // you call _exit() instead of exit(). This is because _exit() does not |
| 415 // call any previously-registered (in the parent) exit handlers, which | 452 // call any previously-registered (in the parent) exit handlers, which |
| 416 // might do things like block waiting for threads that don't even exist | 453 // might do things like block waiting for threads that don't even exist |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 441 } | 478 } |
| 442 } | 479 } |
| 443 | 480 |
| 444 // Stop type-profiler. | 481 // Stop type-profiler. |
| 445 // The profiler should be stopped between fork and exec since it inserts | 482 // The profiler should be stopped between fork and exec since it inserts |
| 446 // locks at new/delete expressions. See http://crbug.com/36678. | 483 // locks at new/delete expressions. See http://crbug.com/36678. |
| 447 base::type_profiler::Controller::Stop(); | 484 base::type_profiler::Controller::Stop(); |
| 448 | 485 |
| 449 if (options.maximize_rlimits) { | 486 if (options.maximize_rlimits) { |
| 450 // Some resource limits need to be maximal in this child. | 487 // Some resource limits need to be maximal in this child. |
| 451 std::set<int>::const_iterator resource; | 488 std::set<int>::const_iterator resource; |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
This could clearly allocate memory :(
crbug.com/2
mdempsky_google
2013/08/02 16:12:51
Iterating over a set can allocate memory?
| |
| 452 for (resource = options.maximize_rlimits->begin(); | 489 for (resource = options.maximize_rlimits->begin(); |
| 453 resource != options.maximize_rlimits->end(); | 490 resource != options.maximize_rlimits->end(); |
| 454 ++resource) { | 491 ++resource) { |
| 455 struct rlimit limit; | 492 struct rlimit limit; |
| 456 if (getrlimit(*resource, &limit) < 0) { | 493 if (getrlimit(*resource, &limit) < 0) { |
| 457 RAW_LOG(WARNING, "getrlimit failed"); | 494 RAW_LOG(WARNING, "getrlimit failed"); |
| 458 } else if (limit.rlim_cur < limit.rlim_max) { | 495 } else if (limit.rlim_cur < limit.rlim_max) { |
| 459 limit.rlim_cur = limit.rlim_max; | 496 limit.rlim_cur = limit.rlim_max; |
| 460 if (setrlimit(*resource, &limit) < 0) { | 497 if (setrlimit(*resource, &limit) < 0) { |
| 461 RAW_LOG(WARNING, "setrlimit failed"); | 498 RAW_LOG(WARNING, "setrlimit failed"); |
| 462 } | 499 } |
| 463 } | 500 } |
| 464 } | 501 } |
| 465 } | 502 } |
| 466 | 503 |
| 467 #if defined(OS_MACOSX) | 504 #if defined(OS_MACOSX) |
| 468 RestoreDefaultExceptionHandler(); | 505 RestoreDefaultExceptionHandler(); |
| 469 #endif // defined(OS_MACOSX) | 506 #endif // defined(OS_MACOSX) |
| 470 | 507 |
| 471 ResetChildSignalHandlersToDefaults(); | 508 ResetChildSignalHandlersToDefaults(); |
| 509 if (!SetSignalMask(&old_sigset, NULL)) { | |
| 510 NOTREACHED(); | |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
RAW_CHECK
| |
| 511 } | |
| 472 | 512 |
| 473 #if 0 | 513 #if 0 |
| 474 // When debugging it can be helpful to check that we really aren't making | 514 // When debugging it can be helpful to check that we really aren't making |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
I guess this was intended right after the fork() b
| |
| 475 // any hidden calls to malloc. | 515 // any hidden calls to malloc. |
| 476 void *malloc_thunk = | 516 void *malloc_thunk = |
| 477 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); | 517 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); |
| 478 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); | 518 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); |
| 479 memset(reinterpret_cast<void*>(malloc), 0xff, 8); | 519 memset(reinterpret_cast<void*>(malloc), 0xff, 8); |
| 480 #endif // 0 | 520 #endif // 0 |
| 481 | 521 |
| 482 // DANGER: no calls to malloc are allowed from now on: | 522 // DANGER: no calls to malloc are allowed from now on: |
| 483 // http://crbug.com/36678 | 523 // http://crbug.com/36678 |
| 484 | 524 |
| 485 #if defined(OS_CHROMEOS) | 525 #if defined(OS_CHROMEOS) |
| 486 if (options.ctrl_terminal_fd >= 0) { | 526 if (options.ctrl_terminal_fd >= 0) { |
| 487 // Set process' controlling terminal. | 527 // Set process' controlling terminal. |
| 488 if (HANDLE_EINTR(setsid()) != -1) { | 528 if (HANDLE_EINTR(setsid()) != -1) { |
| 489 if (HANDLE_EINTR( | 529 if (HANDLE_EINTR( |
| 490 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { | 530 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { |
| 491 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); | 531 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); |
| 492 } | 532 } |
| 493 } else { | 533 } else { |
| 494 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set"); | 534 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set"); |
| 495 } | 535 } |
| 496 } | 536 } |
| 497 #endif // defined(OS_CHROMEOS) | 537 #endif // defined(OS_CHROMEOS) |
| 498 | 538 |
| 499 if (options.fds_to_remap) { | 539 if (options.fds_to_remap) { |
| 500 for (FileHandleMappingVector::const_iterator | 540 for (FileHandleMappingVector::const_iterator |
|
jln (very slow on Chromium)
2013/08/02 05:28:47
Again, this can clearly allocate.
| |
| 501 it = options.fds_to_remap->begin(); | 541 it = options.fds_to_remap->begin(); |
| 502 it != options.fds_to_remap->end(); ++it) { | 542 it != options.fds_to_remap->end(); ++it) { |
| 503 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); | 543 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); |
| 504 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); | 544 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); |
| 505 } | 545 } |
| 506 } | 546 } |
| 507 | 547 |
| 508 if (options.environ) | 548 if (options.environ) |
| 509 SetEnvironment(new_environ.get()); | 549 SetEnvironment(new_environ.get()); |
| 510 | 550 |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 720 std::string* output, | 760 std::string* output, |
| 721 int* exit_code) { | 761 int* exit_code) { |
| 722 // Run |execve()| with the current environment and store "unlimited" data. | 762 // Run |execve()| with the current environment and store "unlimited" data. |
| 723 GetAppOutputInternalResult result = GetAppOutputInternal( | 763 GetAppOutputInternalResult result = GetAppOutputInternal( |
| 724 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, | 764 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, |
| 725 exit_code); | 765 exit_code); |
| 726 return result == EXECUTE_SUCCESS; | 766 return result == EXECUTE_SUCCESS; |
| 727 } | 767 } |
| 728 | 768 |
| 729 } // namespace base | 769 } // namespace base |
| OLD | NEW |