OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |