Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: base/process_util_posix.cc

Issue 672003: POSIX: don't allocate memory after forking. (Closed)
Patch Set: ... Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/process_util.h ('k') | base/process_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 <dirent.h> 5 #include <dirent.h>
6 #include <errno.h> 6 #include <errno.h>
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <signal.h> 8 #include <signal.h>
9 #include <stdlib.h> 9 #include <stdlib.h>
10 #include <sys/resource.h> 10 #include <sys/resource.h>
11 #include <sys/time.h> 11 #include <sys/time.h>
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/wait.h> 13 #include <sys/wait.h>
14 #include <unistd.h> 14 #include <unistd.h>
15 15
16 #include <limits> 16 #include <limits>
17 #include <set> 17 #include <set>
18 18
19 #include "base/compiler_specific.h" 19 #include "base/compiler_specific.h"
20 #include "base/debug_util.h" 20 #include "base/debug_util.h"
21 #include "base/dir_reader_posix.h"
21 #include "base/eintr_wrapper.h" 22 #include "base/eintr_wrapper.h"
22 #include "base/logging.h" 23 #include "base/logging.h"
23 #include "base/platform_thread.h" 24 #include "base/platform_thread.h"
24 #include "base/process_util.h" 25 #include "base/process_util.h"
25 #include "base/rand_util.h" 26 #include "base/rand_util.h"
26 #include "base/scoped_ptr.h" 27 #include "base/scoped_ptr.h"
27 #include "base/sys_info.h" 28 #include "base/sys_info.h"
28 #include "base/time.h" 29 #include "base/time.h"
29 #include "base/waitable_event.h" 30 #include "base/waitable_event.h"
30 31
32
31 #if defined(OS_MACOSX) 33 #if defined(OS_MACOSX)
34 #include <crt_externs.h>
35 #define environ (*_NSGetEnviron())
32 #include "base/mach_ipc_mac.h" 36 #include "base/mach_ipc_mac.h"
37 #else
38 extern char** environ;
33 #endif 39 #endif
34 40
35 const int kMicrosecondsPerSecond = 1000000; 41 const int kMicrosecondsPerSecond = 1000000;
36 42
37 namespace base { 43 namespace base {
38 44
39 namespace { 45 namespace {
40 46
41 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, 47 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
42 bool* success) { 48 bool* success) {
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 class ScopedDIRClose { 172 class ScopedDIRClose {
167 public: 173 public:
168 inline void operator()(DIR* x) const { 174 inline void operator()(DIR* x) const {
169 if (x) { 175 if (x) {
170 closedir(x); 176 closedir(x);
171 } 177 }
172 } 178 }
173 }; 179 };
174 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; 180 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
175 181
176 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
177 #if defined(OS_LINUX) 182 #if defined(OS_LINUX)
178 static const rlim_t kSystemDefaultMaxFds = 8192; 183 static const rlim_t kSystemDefaultMaxFds = 8192;
179 static const char fd_dir[] = "/proc/self/fd"; 184 static const char kFDDir[] = "/proc/self/fd";
180 #elif defined(OS_MACOSX) 185 #elif defined(OS_MACOSX)
181 static const rlim_t kSystemDefaultMaxFds = 256; 186 static const rlim_t kSystemDefaultMaxFds = 256;
182 static const char fd_dir[] = "/dev/fd"; 187 static const char kFDDir[] = "/dev/fd";
183 #elif defined(OS_SOLARIS) 188 #elif defined(OS_SOLARIS)
184 static const rlim_t kSystemDefaultMaxFds = 8192; 189 static const rlim_t kSystemDefaultMaxFds = 8192;
185 static const char fd_dir[] = "/dev/fd"; 190 static const char kFDDir[] = "/dev/fd";
186 #elif defined(OS_FREEBSD) 191 #elif defined(OS_FREEBSD)
187 static const rlim_t kSystemDefaultMaxFds = 8192; 192 static const rlim_t kSystemDefaultMaxFds = 8192;
188 static const char fd_dir[] = "/dev/fd"; 193 static const char kFDDir[] = "/dev/fd";
189 #elif defined(OS_OPENBSD) 194 #elif defined(OS_OPENBSD)
190 static const rlim_t kSystemDefaultMaxFds = 256; 195 static const rlim_t kSystemDefaultMaxFds = 256;
191 static const char fd_dir[] = "/dev/fd"; 196 static const char kFDDir[] = "/dev/fd";
192 #endif 197 #endif
193 std::set<int> saved_fds; 198
199 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
200 // DANGER: no calls to malloc are allowed from now on:
201 // http://crbug.com/36678
194 202
195 // Get the maximum number of FDs possible. 203 // Get the maximum number of FDs possible.
196 struct rlimit nofile; 204 struct rlimit nofile;
197 rlim_t max_fds; 205 rlim_t max_fds;
198 if (getrlimit(RLIMIT_NOFILE, &nofile)) { 206 if (getrlimit(RLIMIT_NOFILE, &nofile)) {
199 // getrlimit failed. Take a best guess. 207 // getrlimit failed. Take a best guess.
200 max_fds = kSystemDefaultMaxFds; 208 max_fds = kSystemDefaultMaxFds;
201 DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno; 209 DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno;
202 } else { 210 } else {
203 max_fds = nofile.rlim_cur; 211 max_fds = nofile.rlim_cur;
204 } 212 }
205 213
206 if (max_fds > INT_MAX) 214 if (max_fds > INT_MAX)
207 max_fds = INT_MAX; 215 max_fds = INT_MAX;
208 216
209 // Don't close stdin, stdout and stderr 217 DirReaderPosix fd_dir(kFDDir);
210 saved_fds.insert(STDIN_FILENO);
211 saved_fds.insert(STDOUT_FILENO);
212 saved_fds.insert(STDERR_FILENO);
213 218
214 for (base::InjectiveMultimap::const_iterator 219 if (!fd_dir.IsValid()) {
215 i = saved_mapping.begin(); i != saved_mapping.end(); ++i) {
216 saved_fds.insert(i->dest);
217 }
218
219 ScopedDIR dir_closer(opendir(fd_dir));
220 DIR *dir = dir_closer.get();
221 if (NULL == dir) {
222 DLOG(ERROR) << "Unable to open " << fd_dir;
223
224 // Fallback case: Try every possible fd. 220 // Fallback case: Try every possible fd.
225 for (rlim_t i = 0; i < max_fds; ++i) { 221 for (rlim_t i = 0; i < max_fds; ++i) {
226 const int fd = static_cast<int>(i); 222 const int fd = static_cast<int>(i);
227 if (saved_fds.find(fd) != saved_fds.end()) 223 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
224 continue;
225 InjectiveMultimap::const_iterator i;
226 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
227 if (fd == i->dest)
228 break;
229 }
230 if (i != saved_mapping.end())
228 continue; 231 continue;
229 232
230 // Since we're just trying to close anything we can find, 233 // Since we're just trying to close anything we can find,
231 // ignore any error return values of close(). 234 // ignore any error return values of close().
232 int unused ALLOW_UNUSED = HANDLE_EINTR(close(fd)); 235 int unused ALLOW_UNUSED = HANDLE_EINTR(close(fd));
233 } 236 }
234 return; 237 return;
235 } 238 }
236 int dir_fd = dirfd(dir);
237 239
238 struct dirent *ent; 240 const int dir_fd = fd_dir.fd();
239 while ((ent = readdir(dir))) { 241
242 for ( ; fd_dir.Next(); ) {
240 // Skip . and .. entries. 243 // Skip . and .. entries.
241 if (ent->d_name[0] == '.') 244 if (fd_dir.name()[0] == '.')
242 continue; 245 continue;
243 246
244 char *endptr; 247 char *endptr;
245 errno = 0; 248 errno = 0;
246 const long int fd = strtol(ent->d_name, &endptr, 10); 249 const long int fd = strtol(fd_dir.name(), &endptr, 10);
247 if (ent->d_name[0] == 0 || *endptr || fd < 0 || errno) 250 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
248 continue; 251 continue;
249 if (saved_fds.find(fd) != saved_fds.end()) 252 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
253 continue;
254 InjectiveMultimap::const_iterator i;
255 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
256 if (fd == i->dest)
257 break;
258 }
259 if (i != saved_mapping.end())
250 continue; 260 continue;
251 if (fd == dir_fd) 261 if (fd == dir_fd)
252 continue; 262 continue;
253 263
254 // When running under Valgrind, Valgrind opens several FDs for its 264 // When running under Valgrind, Valgrind opens several FDs for its
255 // own use and will complain if we try to close them. All of 265 // own use and will complain if we try to close them. All of
256 // these FDs are >= |max_fds|, so we can check against that here 266 // these FDs are >= |max_fds|, so we can check against that here
257 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 267 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
258 if (fd < static_cast<int>(max_fds)) { 268 if (fd < static_cast<int>(max_fds)) {
259 int ret = HANDLE_EINTR(close(fd)); 269 int ret = HANDLE_EINTR(close(fd));
260 DPCHECK(ret == 0); 270 DPCHECK(ret == 0);
261 } 271 }
262 } 272 }
263 } 273 }
264 274
265 // Sets all file descriptors to close on exec except for stdin, stdout
266 // and stderr.
267 // TODO(agl): Remove this function. It's fundamentally broken for multithreaded
268 // apps.
269 void SetAllFDsToCloseOnExec() {
270 #if defined(OS_LINUX)
271 const char fd_dir[] = "/proc/self/fd";
272 #elif defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_SOLARIS)
273 const char fd_dir[] = "/dev/fd";
274 #endif
275 ScopedDIR dir_closer(opendir(fd_dir));
276 DIR *dir = dir_closer.get();
277 if (NULL == dir) {
278 DLOG(ERROR) << "Unable to open " << fd_dir;
279 return;
280 }
281
282 struct dirent *ent;
283 while ((ent = readdir(dir))) {
284 // Skip . and .. entries.
285 if (ent->d_name[0] == '.')
286 continue;
287 int i = atoi(ent->d_name);
288 // We don't close stdin, stdout or stderr.
289 if (i <= STDERR_FILENO)
290 continue;
291
292 int flags = fcntl(i, F_GETFD);
293 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
294 DLOG(ERROR) << "fcntl failure.";
295 }
296 }
297 }
298
299 #if defined(OS_MACOSX) 275 #if defined(OS_MACOSX)
300 static std::string MachErrorCode(kern_return_t err) { 276 static std::string MachErrorCode(kern_return_t err) {
301 return StringPrintf("0x%x %s", err, mach_error_string(err)); 277 return StringPrintf("0x%x %s", err, mach_error_string(err));
302 } 278 }
303 279
304 // Forks the current process and returns the child's |task_t| in the parent 280 // Forks the current process and returns the child's |task_t| in the parent
305 // process. 281 // process.
306 static pid_t fork_and_get_task(task_t* child_task) { 282 static pid_t fork_and_get_task(task_t* child_task) {
307 const int kTimeoutMs = 100; 283 const int kTimeoutMs = 100;
308 kern_return_t err; 284 kern_return_t err;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 return pid; 326 return pid;
351 } 327 }
352 *child_task = child_message.GetTranslatedPort(0); 328 *child_task = child_message.GetTranslatedPort(0);
353 break; 329 break;
354 } 330 }
355 } 331 }
356 return pid; 332 return pid;
357 } 333 }
358 334
359 bool LaunchApp(const std::vector<std::string>& argv, 335 bool LaunchApp(const std::vector<std::string>& argv,
360 const environment_vector& environ, 336 const environment_vector& env_changes,
361 const file_handle_mapping_vector& fds_to_remap, 337 const file_handle_mapping_vector& fds_to_remap,
362 bool wait, ProcessHandle* process_handle) { 338 bool wait, ProcessHandle* process_handle) {
363 return LaunchAppAndGetTask( 339 return LaunchAppAndGetTask(
364 argv, environ, fds_to_remap, wait, NULL, process_handle); 340 argv, env_changes, fds_to_remap, wait, NULL, process_handle);
365 } 341 }
366 #endif // defined(OS_MACOSX) 342 #endif // defined(OS_MACOSX)
367 343
344 // AlterEnvironment returns a modified environment vector, constructed from the
345 // current environment and the list of changes given in |changes|. Each key in
346 // the environment is matched against the first element of the pairs. In the
347 // event of a match, the value is replaced by the second of the pair, unless
348 // the second is empty, in which case the key-value is removed.
349 //
350 // The returned array is allocated using new[] and must be freed by the caller.
351 // Additionally, the first element is also allocated using new[] and should be
352 // freed by the caller.
353 static char** AlterEnvironment(const environment_vector& changes) {
354 unsigned count = 0;
355 unsigned size = 0;
356
357 for (unsigned i = 0; environ[i]; i++) {
358 const char *const pair = environ[i];
359 const char *const equals = strchr(pair, '=');
360 if (!equals) {
361 count++;
362 size += strlen(pair) + 1 /* terminating NUL */;
363 continue;
364 }
365 const unsigned keylen = equals - pair;
366 bool handled = false;
367 for (environment_vector::const_iterator
368 j = changes.begin(); j != changes.end(); j++) {
369 if (j->first.size() == keylen &&
370 memcmp(j->first.data(), pair, keylen) == 0) {
371 if (!j->second.empty()) {
372 count++;
373 size += keylen + 1 /* '=' */ + j->second.size() + 1 /* NUL */;
374 }
375 handled = true;
376 break;
377 }
378 }
379
380 if (!handled) {
381 count++;
382 size += strlen(pair) + 1 /* terminating NUL */;
383 }
384 }
385
386 char **const ret = new char*[count + 1 /* final NULL */];
387 unsigned k = 0;
388 char *scratch = new char[size];
389
390 for (unsigned i = 0; environ[i]; i++) {
391 const char *const pair = environ[i];
392 const char *const equals = strchr(pair, '=');
393 if (!equals) {
394 const unsigned len = strlen(pair);
395 ret[k++] = scratch;
396 memcpy(scratch, pair, len + 1);
397 scratch += len + 1;
398 continue;
399 }
400 const unsigned keylen = equals - pair;
401 bool handled = false;
402 for (environment_vector::const_iterator
403 j = changes.begin(); j != changes.end(); j++) {
404 if (j->first.size() == keylen &&
405 memcmp(j->first.data(), pair, keylen) == 0) {
406 if (!j->second.empty()) {
407 ret[k++] = scratch;
408 memcpy(scratch, pair, keylen + 1);
409 scratch += keylen + 1;
410 memcpy(scratch, j->second.c_str(), j->second.size() + 1);
411 scratch += j->second.size() + 1;
412 }
413 handled = true;
414 break;
415 }
416 }
417
418 if (!handled) {
419 const unsigned len = strlen(pair);
420 ret[k++] = scratch;
421 memcpy(scratch, pair, len + 1);
422 scratch += len + 1;
423 }
424 }
425
426 ret[k] = NULL;
427 return ret;
428 }
429
368 #if defined(OS_MACOSX) 430 #if defined(OS_MACOSX)
369 bool LaunchAppAndGetTask( 431 bool LaunchAppAndGetTask(
370 #else 432 #else
371 bool LaunchApp( 433 bool LaunchApp(
372 #endif 434 #endif
373 const std::vector<std::string>& argv, 435 const std::vector<std::string>& argv,
374 const environment_vector& environ, 436 const environment_vector& env_changes,
375 const file_handle_mapping_vector& fds_to_remap, 437 const file_handle_mapping_vector& fds_to_remap,
376 bool wait, 438 bool wait,
377 #if defined(OS_MACOSX) 439 #if defined(OS_MACOSX)
378 task_t* task_handle, 440 task_t* task_handle,
379 #endif 441 #endif
380 ProcessHandle* process_handle) { 442 ProcessHandle* process_handle) {
381 pid_t pid; 443 pid_t pid;
444 InjectiveMultimap fd_shuffle1, fd_shuffle2;
445 fd_shuffle1.reserve(fds_to_remap.size());
446 fd_shuffle2.reserve(fds_to_remap.size());
447 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
448 scoped_array<char*> new_environ(AlterEnvironment(env_changes));
449 // We need to free both the array of pointers, and the memory that they're
450 // all pointing into.
451 scoped_array<char> environ_buffer(new_environ[0]);
452
382 #if defined(OS_MACOSX) 453 #if defined(OS_MACOSX)
383 if (task_handle == NULL) { 454 if (task_handle == NULL) {
384 pid = fork(); 455 pid = fork();
385 } else { 456 } else {
386 // On OS X, the task_t for a process is needed for several reasons. Sadly, 457 // On OS X, the task_t for a process is needed for several reasons. Sadly,
387 // the function task_for_pid() requires privileges a normal user doesn't 458 // the function task_for_pid() requires privileges a normal user doesn't
388 // have. Instead, a short-lived Mach IPC connection is opened between parent 459 // have. Instead, a short-lived Mach IPC connection is opened between parent
389 // and child, and the child sends its task_t to the parent at fork time. 460 // and child, and the child sends its task_t to the parent at fork time.
390 *task_handle = MACH_PORT_NULL; 461 *task_handle = MACH_PORT_NULL;
391 pid = fork_and_get_task(task_handle); 462 pid = fork_and_get_task(task_handle);
392 } 463 }
393 #else 464 #else
394 pid = fork(); 465 pid = fork();
395 #endif 466 #endif
396 if (pid < 0) 467 if (pid < 0)
397 return false; 468 return false;
398 469
399 if (pid == 0) { 470 if (pid == 0) {
400 // Child process 471 // Child process
401 #if defined(OS_MACOSX) 472 #if defined(OS_MACOSX)
402 RestoreDefaultExceptionHandler(); 473 RestoreDefaultExceptionHandler();
403 #endif 474 #endif
404 475
405 InjectiveMultimap fd_shuffle; 476 #if 0
477 // When debugging it can be helpful to check that we really aren't making
478 // any hidden calls to malloc.
479 void *malloc_thunk =
480 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
481 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
482 memset(reinterpret_cast<void*>(malloc), 0xff, 8);
483 #endif
484
485 // DANGER: no calls to malloc are allowed from now on:
486 // http://crbug.com/36678
487
406 for (file_handle_mapping_vector::const_iterator 488 for (file_handle_mapping_vector::const_iterator
407 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { 489 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
408 fd_shuffle.push_back(InjectionArc(it->first, it->second, false)); 490 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false));
491 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false));
409 } 492 }
410 493
411 for (environment_vector::const_iterator it = environ.begin(); 494 environ = new_environ.get();
412 it != environ.end(); ++it) {
413 if (it->first.empty())
414 continue;
415
416 if (it->second.empty()) {
417 unsetenv(it->first.c_str());
418 } else {
419 setenv(it->first.c_str(), it->second.c_str(), 1);
420 }
421 }
422 495
423 // Obscure fork() rule: in the child, if you don't end up doing exec*(), 496 // Obscure fork() rule: in the child, if you don't end up doing exec*(),
424 // you call _exit() instead of exit(). This is because _exit() does not 497 // you call _exit() instead of exit(). This is because _exit() does not
425 // call any previously-registered (in the parent) exit handlers, which 498 // call any previously-registered (in the parent) exit handlers, which
426 // might do things like block waiting for threads that don't even exist 499 // might do things like block waiting for threads that don't even exist
427 // in the child. 500 // in the child.
428 if (!ShuffleFileDescriptors(fd_shuffle)) 501
502 // fd_shuffle1 is mutated by this call because it cannot malloc.
503 if (!ShuffleFileDescriptors(&fd_shuffle1))
429 _exit(127); 504 _exit(127);
430 505
431 // If we are using the SUID sandbox, it sets a magic environment variable 506 CloseSuperfluousFds(fd_shuffle2);
432 // ("SBX_D"), so we remove that variable from the environment here on the
433 // off chance that it's already set.
434 unsetenv("SBX_D");
435 507
436 CloseSuperfluousFds(fd_shuffle);
437
438 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
439 for (size_t i = 0; i < argv.size(); i++) 508 for (size_t i = 0; i < argv.size(); i++)
440 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); 509 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
441 argv_cstr[argv.size()] = NULL; 510 argv_cstr[argv.size()] = NULL;
442 execvp(argv_cstr[0], argv_cstr.get()); 511 execvp(argv_cstr[0], argv_cstr.get());
443 PLOG(ERROR) << "LaunchApp: execvp(" << argv_cstr[0] << ") failed"; 512 RAW_LOG(ERROR, "LaunchApp: failed to execvp:");
513 RAW_LOG(ERROR, argv_cstr[0]);
444 _exit(127); 514 _exit(127);
445 } else { 515 } else {
446 // Parent process 516 // Parent process
447 if (wait) { 517 if (wait) {
448 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); 518 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
449 DPCHECK(ret > 0); 519 DPCHECK(ret > 0);
450 } 520 }
451 521
452 if (process_handle) 522 if (process_handle)
453 *process_handle = pid; 523 *process_handle = pid;
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 // the current environment. If |do_search_path| is false, |cl| should fully 696 // the current environment. If |do_search_path| is false, |cl| should fully
627 // specify the path of the application, and |envp| will be used as the 697 // specify the path of the application, and |envp| will be used as the
628 // environment. Redirects stderr to /dev/null. Returns true on success 698 // environment. Redirects stderr to /dev/null. Returns true on success
629 // (application launched and exited cleanly, with exit code indicating success). 699 // (application launched and exited cleanly, with exit code indicating success).
630 // |output| is modified only when the function finished successfully. 700 // |output| is modified only when the function finished successfully.
631 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], 701 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[],
632 std::string* output, size_t max_output, 702 std::string* output, size_t max_output,
633 bool do_search_path) { 703 bool do_search_path) {
634 int pipe_fd[2]; 704 int pipe_fd[2];
635 pid_t pid; 705 pid_t pid;
706 InjectiveMultimap fd_shuffle1, fd_shuffle2;
707 const std::vector<std::string>& argv = cl.argv();
708 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
709
710 fd_shuffle1.reserve(3);
711 fd_shuffle2.reserve(3);
636 712
637 // Either |do_search_path| should be false or |envp| should be null, but not 713 // Either |do_search_path| should be false or |envp| should be null, but not
638 // both. 714 // both.
639 DCHECK(!do_search_path ^ !envp); 715 DCHECK(!do_search_path ^ !envp);
640 716
641 if (pipe(pipe_fd) < 0) 717 if (pipe(pipe_fd) < 0)
642 return false; 718 return false;
643 719
644 switch (pid = fork()) { 720 switch (pid = fork()) {
645 case -1: // error 721 case -1: // error
646 close(pipe_fd[0]); 722 close(pipe_fd[0]);
647 close(pipe_fd[1]); 723 close(pipe_fd[1]);
648 return false; 724 return false;
649 case 0: // child 725 case 0: // child
650 { 726 {
651 #if defined(OS_MACOSX) 727 #if defined(OS_MACOSX)
652 RestoreDefaultExceptionHandler(); 728 RestoreDefaultExceptionHandler();
653 #endif 729 #endif
730 // DANGER: no calls to malloc are allowed from now on:
731 // http://crbug.com/36678
654 732
655 // Obscure fork() rule: in the child, if you don't end up doing exec*(), 733 // Obscure fork() rule: in the child, if you don't end up doing exec*(),
656 // you call _exit() instead of exit(). This is because _exit() does not 734 // you call _exit() instead of exit(). This is because _exit() does not
657 // call any previously-registered (in the parent) exit handlers, which 735 // call any previously-registered (in the parent) exit handlers, which
658 // might do things like block waiting for threads that don't even exist 736 // might do things like block waiting for threads that don't even exist
659 // in the child. 737 // in the child.
660 int dev_null = open("/dev/null", O_WRONLY); 738 int dev_null = open("/dev/null", O_WRONLY);
661 if (dev_null < 0) 739 if (dev_null < 0)
662 _exit(127); 740 _exit(127);
663 741
664 InjectiveMultimap fd_shuffle; 742 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
665 fd_shuffle.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); 743 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
666 fd_shuffle.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); 744 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
667 fd_shuffle.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); 745 // Adding another element here? Remeber to increase the argument to
746 // reserve(), above.
668 747
669 if (!ShuffleFileDescriptors(fd_shuffle)) 748 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
749 std::back_inserter(fd_shuffle2));
750
751 if (!ShuffleFileDescriptors(&fd_shuffle1))
670 _exit(127); 752 _exit(127);
671 753
672 CloseSuperfluousFds(fd_shuffle); 754 CloseSuperfluousFds(fd_shuffle2);
673 755
674 const std::vector<std::string> argv = cl.argv();
675 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
676 for (size_t i = 0; i < argv.size(); i++) 756 for (size_t i = 0; i < argv.size(); i++)
677 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); 757 argv_cstr[i] = const_cast<char*>(argv[i].c_str());
678 argv_cstr[argv.size()] = NULL; 758 argv_cstr[argv.size()] = NULL;
679 if (do_search_path) 759 if (do_search_path)
680 execvp(argv_cstr[0], argv_cstr.get()); 760 execvp(argv_cstr[0], argv_cstr.get());
681 else 761 else
682 execve(argv_cstr[0], argv_cstr.get(), envp); 762 execve(argv_cstr[0], argv_cstr.get(), envp);
683 _exit(127); 763 _exit(127);
684 } 764 }
685 default: // parent 765 default: // parent
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 const ProcessFilter* filter) { 867 const ProcessFilter* filter) {
788 bool exited_cleanly = 868 bool exited_cleanly =
789 WaitForProcessesToExit(executable_name, wait_milliseconds, 869 WaitForProcessesToExit(executable_name, wait_milliseconds,
790 filter); 870 filter);
791 if (!exited_cleanly) 871 if (!exited_cleanly)
792 KillProcesses(executable_name, exit_code, filter); 872 KillProcesses(executable_name, exit_code, filter);
793 return exited_cleanly; 873 return exited_cleanly;
794 } 874 }
795 875
796 } // namespace base 876 } // namespace base
OLDNEW
« no previous file with comments | « base/process_util.h ('k') | base/process_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698