passenger 4.0.0.rc4 → 4.0.0.rc6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (83) hide show
  1. data.tar.gz.asc +12 -0
  2. data/.travis.yml +4 -4
  3. data/NEWS +46 -0
  4. data/bin/passenger-config +31 -1
  5. data/bin/passenger-install-apache2-module +1 -1
  6. data/bin/passenger-install-nginx-module +1 -0
  7. data/build/common_library.rb +4 -0
  8. data/build/cplusplus_support.rb +27 -6
  9. data/build/cxx_tests.rb +1 -1
  10. data/build/misc.rb +28 -6
  11. data/build/packaging.rb +72 -65
  12. data/build/test_basics.rb +1 -1
  13. data/dev/googlecode_upload.py +265 -0
  14. data/dev/run_travis.sh +9 -0
  15. data/doc/Users guide Apache.html +376 -193
  16. data/doc/Users guide Apache.idmap.txt +80 -62
  17. data/doc/Users guide Apache.txt +61 -35
  18. data/doc/Users guide Nginx.html +278 -83
  19. data/doc/Users guide Nginx.idmap.txt +26 -10
  20. data/doc/Users guide Nginx.txt +59 -31
  21. data/doc/Users guide Standalone.html +1 -1
  22. data/doc/users_guide_snippets/installation.txt +121 -11
  23. data/doc/users_guide_snippets/rvm_helper_tool.txt +56 -0
  24. data/ext/apache2/Bucket.cpp +1 -1
  25. data/ext/apache2/Configuration.cpp +7 -1
  26. data/ext/apache2/Configuration.hpp +4 -0
  27. data/ext/apache2/Hooks.cpp +2 -2
  28. data/ext/common/AgentsStarter.cpp +2 -2
  29. data/ext/common/AgentsStarter.h +1 -1
  30. data/ext/common/AgentsStarter.hpp +2 -2
  31. data/ext/common/ApplicationPool2/DirectSpawner.h +4 -8
  32. data/ext/common/ApplicationPool2/Group.h +17 -11
  33. data/ext/common/ApplicationPool2/Implementation.cpp +39 -11
  34. data/ext/common/ApplicationPool2/Pool.h +23 -4
  35. data/ext/common/ApplicationPool2/Process.h +30 -11
  36. data/ext/common/ApplicationPool2/SmartSpawner.h +3 -1
  37. data/ext/common/Constants.h +1 -1
  38. data/ext/common/EventedBufferedInput.h +4 -0
  39. data/ext/common/Utils.cpp +21 -3
  40. data/ext/common/Utils.h +8 -1
  41. data/ext/common/Utils/HttpHeaderBufferer.h +1 -1
  42. data/ext/common/Utils/IOUtils.cpp +5 -4
  43. data/ext/common/Utils/IOUtils.h +32 -14
  44. data/ext/common/Utils/MessagePassing.h +2 -2
  45. data/ext/common/Utils/ProcessMetricsCollector.h +47 -15
  46. data/ext/common/Utils/ScopeGuard.h +20 -3
  47. data/ext/common/Utils/StrIntUtils.h +14 -5
  48. data/ext/common/agents/Base.cpp +161 -50
  49. data/ext/common/agents/HelperAgent/AgentOptions.h +2 -2
  50. data/ext/common/agents/HelperAgent/Main.cpp +1 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler.h +166 -52
  52. data/ext/common/agents/LoggingAgent/Main.cpp +1 -1
  53. data/ext/common/agents/Watchdog/Main.cpp +2 -2
  54. data/ext/nginx/Configuration.c +31 -4
  55. data/ext/nginx/Configuration.h +1 -0
  56. data/ext/nginx/ContentHandler.c +148 -34
  57. data/ext/nginx/ngx_http_passenger_module.c +4 -1
  58. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  59. data/ext/oxt/macros.hpp +30 -8
  60. data/lib/phusion_passenger.rb +2 -2
  61. data/lib/phusion_passenger/classic_rails/thread_handler_extension.rb +1 -1
  62. data/lib/phusion_passenger/native_support.rb +19 -1
  63. data/lib/phusion_passenger/platform_info/compiler.rb +6 -0
  64. data/lib/phusion_passenger/platform_info/ruby.rb +54 -5
  65. data/lib/phusion_passenger/preloader_shared_helpers.rb +8 -1
  66. data/lib/phusion_passenger/rack/out_of_band_gc.rb +3 -1
  67. data/lib/phusion_passenger/rack/thread_handler_extension.rb +32 -5
  68. data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -8
  69. data/lib/phusion_passenger/ruby_core_enhancements.rb +9 -1
  70. data/lib/phusion_passenger/standalone/runtime_installer.rb +1 -0
  71. data/lib/phusion_passenger/utils/unseekable_socket.rb +50 -5
  72. data/passenger.gemspec +1 -1
  73. data/resources/templates/apache2/config_snippets.txt.erb +1 -1
  74. data/test/cxx/ApplicationPool2/PoolTest.cpp +4 -9
  75. data/test/cxx/RequestHandlerTest.cpp +5 -5
  76. data/test/ruby/classic_rails/loader_spec.rb +1 -1
  77. data/test/ruby/classic_rails/preloader_spec.rb +1 -1
  78. data/test/ruby/request_handler_spec.rb +207 -1
  79. data/test/ruby/shared/loader_sharedspec.rb +1 -0
  80. data/test/ruby/spec_helper.rb +11 -1
  81. data/test/stub/apache2/httpd.conf.erb +1 -1
  82. metadata +5 -3
  83. metadata.gz.asc +12 -0
@@ -27,11 +27,14 @@
27
27
 
28
28
  #include <boost/noncopyable.hpp>
29
29
  #include <boost/function.hpp>
30
+ #include <boost/thread.hpp>
31
+ #include <oxt/system_calls.hpp>
30
32
  #include <cstdio>
31
33
 
32
34
  namespace Passenger {
33
35
 
34
36
  using namespace boost;
37
+ using namespace oxt;
35
38
 
36
39
 
37
40
  #ifndef _PASSENGER_SAFELY_CLOSE_DEFINED_
@@ -48,17 +51,25 @@ using namespace boost;
48
51
  class ScopeGuard: public noncopyable {
49
52
  private:
50
53
  function<void ()> func;
54
+ bool interruptable;
51
55
 
52
56
  public:
53
57
  ScopeGuard() { }
54
58
 
55
- ScopeGuard(const function<void ()> &func) {
59
+ ScopeGuard(const function<void ()> &func, bool interruptable = false) {
56
60
  this->func = func;
61
+ this->interruptable = interruptable;
57
62
  }
58
63
 
59
64
  ~ScopeGuard() {
60
65
  if (func) {
61
- func();
66
+ if (interruptable) {
67
+ func();
68
+ } else {
69
+ this_thread::disable_interruption di;
70
+ this_thread::disable_syscall_interruption dsi;
71
+ func();
72
+ }
62
73
  }
63
74
  }
64
75
 
@@ -69,7 +80,13 @@ public:
69
80
  void runNow() {
70
81
  function<void ()> oldFunc = func;
71
82
  func = function<void()>();
72
- oldFunc();
83
+ if (interruptable) {
84
+ oldFunc();
85
+ } else {
86
+ this_thread::disable_interruption di;
87
+ this_thread::disable_syscall_interruption dsi;
88
+ oldFunc();
89
+ }
73
90
  }
74
91
  };
75
92
 
@@ -30,6 +30,7 @@
30
30
  #include <sstream>
31
31
  #include <cstddef>
32
32
  #include <ctime>
33
+ #include <oxt/macros.hpp>
33
34
  #include <StaticString.h>
34
35
 
35
36
  namespace Passenger {
@@ -74,8 +75,12 @@ bool startsWith(const StaticString &str, const StaticString &substr);
74
75
  * @param sep The separator to use.
75
76
  * @param output The vector to write the output to.
76
77
  */
77
- void split(const StaticString &str, char sep, vector<string> &output);
78
- void split(const StaticString &str, char sep, vector<StaticString> &output);
78
+ void split(const StaticString & restrict_ref str,
79
+ char sep,
80
+ vector<string> & restrict_ref output);
81
+ void split(const StaticString & restrict_ref str,
82
+ char sep,
83
+ vector<StaticString> & restrict_ref output);
79
84
 
80
85
  /**
81
86
  * Split the given string using the given separator. Includes the
@@ -85,8 +90,12 @@ void split(const StaticString &str, char sep, vector<StaticString> &output);
85
90
  * @param sep The separator to use.
86
91
  * @param output The vector to write the output to.
87
92
  */
88
- void splitIncludeSep(const StaticString &str, char sep, vector<string> &output);
89
- void splitIncludeSep(const StaticString &str, char sep, vector<StaticString> &output);
93
+ void splitIncludeSep(const StaticString & restrict_ref str,
94
+ char sep,
95
+ vector<string> & restrict_ref output);
96
+ void splitIncludeSep(const StaticString & restrict_ref str,
97
+ char sep,
98
+ vector<StaticString> & restrict_ref output);
90
99
 
91
100
  /**
92
101
  * Look for 'toFind' inside 'str', replace it with 'replaceWith' and return the result.
@@ -146,7 +155,7 @@ string toHex(const StaticString &data);
146
155
  * Convert the given binary data to hexadecimal. This form accepts an
147
156
  * output buffer which must be at least <tt>data.size() * 2</tt> bytes large.
148
157
  */
149
- void toHex(const StaticString &data, char *output, bool upperCase = false);
158
+ void toHex(const StaticString & restrict_ref data, char * restrict output, bool upperCase = false);
150
159
 
151
160
  /**
152
161
  * Convert the given integer to some other radix, placing
@@ -60,6 +60,7 @@
60
60
  #include <Constants.h>
61
61
  #include <Exceptions.h>
62
62
  #include <Logging.h>
63
+ #include <ResourceLocator.h>
63
64
  #include <Utils.h>
64
65
  #include <Utils/StrIntUtils.h>
65
66
  #ifdef __linux__
@@ -101,12 +102,17 @@ static unsigned int alternativeStackSize;
101
102
  static volatile unsigned int abortHandlerCalled = 0;
102
103
  static unsigned int randomSeed = 0;
103
104
  static const char *argv0 = NULL;
104
- static const char *backtraceSanitizerPath = NULL;
105
- static bool backtraceSanitizerUseShell = false;
105
+ static const char *backtraceSanitizerCommand = NULL;
106
106
  static bool backtraceSanitizerPassProgramInfo = true;
107
107
  static DiagnosticsDumper customDiagnosticsDumper = NULL;
108
108
  static void *customDiagnosticsDumperUserData;
109
109
 
110
+ // We preallocate a few pipes during startup which we will close in the
111
+ // crash handler. This way we can be sure that when the crash handler
112
+ // calls pipe() it won't fail with "Too many files".
113
+ static int emergencyPipe1[2] = { -1, -1 };
114
+ static int emergencyPipe2[2] = { -1, -1 };
115
+
110
116
  // If assert() failed, its information is stored here.
111
117
  static struct {
112
118
  const char *filename;
@@ -143,17 +149,6 @@ hasEnvOption(const char *name, bool defaultValue = false) {
143
149
  }
144
150
  }
145
151
 
146
- // Async-signal safe way to fork().
147
- // http://sourceware.org/bugzilla/show_bug.cgi?id=4737
148
- static pid_t
149
- asyncFork() {
150
- #if defined(__linux__)
151
- return (pid_t) syscall(SYS_fork);
152
- #else
153
- return fork();
154
- #endif
155
- }
156
-
157
152
  // No idea whether strlen() is async signal safe, but let's not risk it
158
153
  // and write our own version instead that's guaranteed to be safe.
159
154
  static size_t
@@ -361,7 +356,7 @@ appendSignalReason(char *buf, siginfo_t *info) {
361
356
  return buf;
362
357
  }
363
358
 
364
- static void
359
+ static int
365
360
  runInSubprocessWithTimeLimit(AbortHandlerState &state, Callback callback, void *userData, int timeLimit) {
366
361
  char *end;
367
362
  pid_t child;
@@ -370,11 +365,11 @@ runInSubprocessWithTimeLimit(AbortHandlerState &state, Callback callback, void *
370
365
  if (pipe(p) == -1) {
371
366
  e = errno;
372
367
  end = state.messageBuf;
373
- end = appendText(end, "Could not dump diagnostics: pipe() failed with errno=");
368
+ end = appendText(end, "Could not create subprocess: pipe() failed with errno=");
374
369
  end = appendULL(end, e);
375
370
  end = appendText(end, "\n");
376
371
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
377
- return;
372
+ return -1;
378
373
  }
379
374
 
380
375
  child = asyncFork();
@@ -382,18 +377,21 @@ runInSubprocessWithTimeLimit(AbortHandlerState &state, Callback callback, void *
382
377
  close(p[0]);
383
378
  callback(state, userData);
384
379
  _exit(0);
380
+ return -1;
385
381
 
386
382
  } else if (child == -1) {
387
383
  e = errno;
388
384
  close(p[0]);
389
385
  close(p[1]);
390
386
  end = state.messageBuf;
391
- end = appendText(end, "Could not dump diagnostics: fork() failed with errno=");
387
+ end = appendText(end, "Could not create subprocess: fork() failed with errno=");
392
388
  end = appendULL(end, e);
393
389
  end = appendText(end, "\n");
394
390
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
391
+ return -1;
395
392
 
396
393
  } else {
394
+ int status;
397
395
  close(p[1]);
398
396
 
399
397
  // We give the child process a time limit. If it doesn't succeed in
@@ -404,10 +402,91 @@ runInSubprocessWithTimeLimit(AbortHandlerState &state, Callback callback, void *
404
402
  fd.events = POLLIN | POLLHUP | POLLERR;
405
403
  if (poll(&fd, 1, timeLimit) <= 0) {
406
404
  kill(child, SIGKILL);
407
- safePrintErr("Could not dump diagnostics: child process did not exit in time\n");
405
+ safePrintErr("Could not run child process: it did not exit in time\n");
408
406
  }
409
407
  close(p[0]);
410
- waitpid(child, NULL, 0);
408
+ if (waitpid(child, &status, 0) == child) {
409
+ return status;
410
+ } else {
411
+ return -1;
412
+ }
413
+ }
414
+ }
415
+
416
+ static void
417
+ dumpFileDescriptorInfoWithLsof(AbortHandlerState &state, void *userData) {
418
+ char *end;
419
+
420
+ end = state.messageBuf;
421
+ end = appendULL(end, state.pid);
422
+ *end = '\0';
423
+
424
+ closeAllFileDescriptors(2);
425
+
426
+ execlp("lsof", "lsof", "-p", state.messageBuf, "-nP", (const char * const) 0);
427
+
428
+ end = state.messageBuf;
429
+ end = appendText(end, "ERROR: cannot execute command 'lsof': errno=");
430
+ end = appendULL(end, errno);
431
+ end = appendText(end, "\n");
432
+ write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
433
+ _exit(1);
434
+ }
435
+
436
+ static void
437
+ dumpFileDescriptorInfoWithLs(AbortHandlerState &state, char *end) {
438
+ pid_t pid;
439
+ int status;
440
+
441
+ pid = asyncFork();
442
+ if (pid == 0) {
443
+ closeAllFileDescriptors(2);
444
+ // The '-v' is for natural sorting on Linux. On BSD -v means something else but it's harmless.
445
+ execlp("ls", "ls", "-lv", state.messageBuf, (const char * const) 0);
446
+ _exit(1);
447
+ } else if (pid == -1) {
448
+ safePrintErr("ERROR: Could not fork a process to dump file descriptor information!\n");
449
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
450
+ safePrintErr("ERROR: Could not run 'ls' to dump file descriptor information!\n");
451
+ }
452
+ }
453
+
454
+ static void
455
+ dumpFileDescriptorInfo(AbortHandlerState &state) {
456
+ char *messageBuf = state.messageBuf;
457
+ char *end;
458
+ struct stat buf;
459
+ int status;
460
+
461
+ end = messageBuf;
462
+ end = appendText(end, state.messagePrefix);
463
+ end = appendText(end, " ] Open files and file descriptors:\n");
464
+ write(STDERR_FILENO, messageBuf, end - messageBuf);
465
+
466
+ status = runInSubprocessWithTimeLimit(state, dumpFileDescriptorInfoWithLsof, NULL, 4000);
467
+
468
+ if (status != 0) {
469
+ safePrintErr("Falling back to another mechanism for dumping file descriptors.\n");
470
+
471
+ end = messageBuf;
472
+ end = appendText(end, "/proc/");
473
+ end = appendULL(end, state.pid);
474
+ end = appendText(end, "/fd");
475
+ *end = '\0';
476
+ if (stat(messageBuf, &buf) == 0) {
477
+ dumpFileDescriptorInfoWithLs(state, end + 1);
478
+ } else {
479
+ end = messageBuf;
480
+ end = appendText(end, "/dev/fd");
481
+ *end = '\0';
482
+ if (stat(messageBuf, &buf) == 0) {
483
+ dumpFileDescriptorInfoWithLs(state, end + 1);
484
+ } else {
485
+ end = messageBuf;
486
+ end = appendText(end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
487
+ write(STDERR_FILENO, messageBuf, end - messageBuf);
488
+ }
489
+ }
411
490
  }
412
491
  }
413
492
 
@@ -421,6 +500,7 @@ dumpWithCrashWatch(AbortHandlerState &state) {
421
500
 
422
501
  pid_t child = asyncFork();
423
502
  if (child == 0) {
503
+ closeAllFileDescriptors(2);
424
504
  execlp("crash-watch", "crash-watch", "--dump", pidStr, (char * const) 0);
425
505
  if (errno == ENOENT) {
426
506
  safePrintErr("Crash-watch is not installed. Please install it with 'gem install crash-watch' "
@@ -463,7 +543,7 @@ dumpWithCrashWatch(AbortHandlerState &state) {
463
543
  end = appendText(end, " frames:\n");
464
544
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
465
545
 
466
- if (backtraceSanitizerPath != NULL) {
546
+ if (backtraceSanitizerCommand != NULL) {
467
547
  int p[2];
468
548
  if (pipe(p) == -1) {
469
549
  int e = errno;
@@ -482,34 +562,28 @@ dumpWithCrashWatch(AbortHandlerState &state) {
482
562
  const char *pidStr = end = state.messageBuf;
483
563
  end = appendULL(end, (unsigned long long) state.pid);
484
564
  *end = '\0';
565
+ end++;
485
566
 
486
567
  close(p[1]);
487
568
  dup2(p[0], STDIN_FILENO);
488
- if (backtraceSanitizerUseShell) {
489
- end = state.messageBuf;
490
- end = appendText(end, backtraceSanitizerPath);
491
- if (backtraceSanitizerPassProgramInfo) {
492
- end = appendText(end, " \"");
493
- end = appendText(end, argv0);
494
- end = appendText(end, "\" ");
495
- end = appendText(end, pidStr);
496
- }
497
- *end = '\0';
498
- execlp("/bin/sh", "/bin/sh", "-c",
499
- state.messageBuf, (const char * const) 0);
500
- } else {
501
- if (backtraceSanitizerPassProgramInfo) {
502
- execlp(backtraceSanitizerPath, backtraceSanitizerPath, argv0,
503
- pidStr, (const char * const) 0);
504
- } else {
505
- execlp(backtraceSanitizerPath, backtraceSanitizerPath,
506
- (const char * const) 0);
507
- }
569
+ closeAllFileDescriptors(2);
570
+
571
+ char *command = end;
572
+ end = appendText(end, "exec ");
573
+ end = appendText(end, backtraceSanitizerCommand);
574
+ if (backtraceSanitizerPassProgramInfo) {
575
+ end = appendText(end, " \"");
576
+ end = appendText(end, argv0);
577
+ end = appendText(end, "\" ");
578
+ end = appendText(end, pidStr);
508
579
  }
580
+ *end = '\0';
581
+ end++;
582
+ execlp("/bin/sh", "/bin/sh", "-c", command, (const char * const) 0);
509
583
 
510
584
  end = state.messageBuf;
511
585
  end = appendText(end, "ERROR: cannot execute '");
512
- end = appendText(end, backtraceSanitizerPath);
586
+ end = appendText(end, backtraceSanitizerCommand);
513
587
  end = appendText(end, "' for sanitizing the backtrace, trying 'cat'...\n");
514
588
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
515
589
  execlp("cat", "cat", (const char * const) 0);
@@ -539,7 +613,7 @@ dumpWithCrashWatch(AbortHandlerState &state) {
539
613
  if (waitpid(pid, &status, 0) == -1 || status != 0) {
540
614
  end = state.messageBuf;
541
615
  end = appendText(end, "ERROR: cannot execute '");
542
- end = appendText(end, backtraceSanitizerPath);
616
+ end = appendText(end, backtraceSanitizerCommand);
543
617
  end = appendText(end, "' for sanitizing the backtrace, writing to stderr directly...\n");
544
618
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
545
619
  backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
@@ -563,27 +637,49 @@ dumpDiagnostics(AbortHandlerState &state) {
563
637
  char *messageBuf = state.messageBuf;
564
638
  char *end;
565
639
  pid_t pid;
640
+ int status;
641
+
642
+ end = messageBuf;
643
+ end = appendText(end, state.messagePrefix);
644
+ end = appendText(end, " ] Date, uname and ulimits:\n");
645
+ write(STDERR_FILENO, messageBuf, end - messageBuf);
566
646
 
567
647
  // Dump human-readable time string and string.
568
648
  pid = asyncFork();
569
649
  if (pid == 0) {
650
+ closeAllFileDescriptors(2);
570
651
  execlp("date", "date", (const char * const) 0);
571
652
  _exit(1);
572
653
  } else if (pid == -1) {
573
654
  safePrintErr("ERROR: Could not fork a process to dump the time!\n");
574
- } else {
575
- waitpid(pid, NULL, 0);
655
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
656
+ safePrintErr("ERROR: Could not run 'date'!\n");
576
657
  }
577
658
 
578
659
  // Dump system uname.
579
660
  pid = asyncFork();
580
661
  if (pid == 0) {
662
+ closeAllFileDescriptors(2);
581
663
  execlp("uname", "uname", "-mprsv", (const char * const) 0);
582
664
  _exit(1);
583
665
  } else if (pid == -1) {
584
666
  safePrintErr("ERROR: Could not fork a process to dump the uname!\n");
585
- } else {
586
- waitpid(pid, NULL, 0);
667
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
668
+ safePrintErr("ERROR: Could not run 'uname -mprsv'!\n");
669
+ }
670
+
671
+ // Dump ulimit.
672
+ pid = asyncFork();
673
+ if (pid == 0) {
674
+ closeAllFileDescriptors(2);
675
+ execlp("ulimit", "ulimit", "-a", (const char * const) 0);
676
+ // On Linux 'ulimit' is a shell builtin, not a command.
677
+ execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (const char * const) 0);
678
+ _exit(1);
679
+ } else if (pid == -1) {
680
+ safePrintErr("ERROR: Could not fork a process to dump the ulimit!\n");
681
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
682
+ safePrintErr("ERROR: Could not run 'ulimit -a'!\n");
587
683
  }
588
684
 
589
685
  end = messageBuf;
@@ -638,6 +734,9 @@ dumpDiagnostics(AbortHandlerState &state) {
638
734
  safePrintErr("--------------------------------------\n");
639
735
  }
640
736
 
737
+ dumpFileDescriptorInfo(state);
738
+ safePrintErr("--------------------------------------\n");
739
+
641
740
  if (shouldDumpWithCrashWatch) {
642
741
  end = messageBuf;
643
742
  end = appendText(end, state.messagePrefix);
@@ -753,6 +852,13 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
753
852
  return;
754
853
  }
755
854
 
855
+ close(emergencyPipe1[0]);
856
+ close(emergencyPipe1[1]);
857
+ close(emergencyPipe2[0]);
858
+ close(emergencyPipe2[1]);
859
+ emergencyPipe1[0] = emergencyPipe1[1] = -1;
860
+ emergencyPipe2[0] = emergencyPipe2[1] = -1;
861
+
756
862
  /* We want to dump the entire crash log to both stderr and a log file.
757
863
  * We use 'tee' for this.
758
864
  */
@@ -798,6 +904,7 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
798
904
 
799
905
  child = asyncFork();
800
906
  if (child == 0) {
907
+ closeAllFileDescriptors(2);
801
908
  #ifdef __APPLE__
802
909
  execlp("osascript", "osascript", "-e", "beep 2", (const char * const) 0);
803
910
  safePrintErr("Cannot execute 'osascript' command\n");
@@ -1338,6 +1445,8 @@ initializeAgent(int argc, char *argv[], const char *processName) {
1338
1445
  shouldDumpWithCrashWatch = hasEnvOption("PASSENGER_DUMP_WITH_CRASH_WATCH", true);
1339
1446
  beepOnAbort = hasEnvOption("PASSENGER_BEEP_ON_ABORT", false);
1340
1447
  stopOnAbort = hasEnvOption("PASSENGER_STOP_ON_ABORT", false);
1448
+ pipe(emergencyPipe1);
1449
+ pipe(emergencyPipe2);
1341
1450
  installAbortHandler();
1342
1451
  }
1343
1452
  oxt::initialize();
@@ -1380,12 +1489,14 @@ initializeAgent(int argc, char *argv[], const char *processName) {
1380
1489
  #ifdef __linux__
1381
1490
  if (options.has("passenger_root")) {
1382
1491
  ResourceLocator locator(options.get("passenger_root", true));
1383
- backtraceSanitizerPath = strdup((locator.getHelperScriptsDir() + "/backtrace-sanitizer.rb").c_str());
1492
+ string ruby = options.get("default_ruby", false, DEFAULT_RUBY);
1493
+ string path = ruby + " \"" + locator.getHelperScriptsDir() +
1494
+ "/backtrace-sanitizer.rb\"";
1495
+ backtraceSanitizerCommand = strdup(path.c_str());
1384
1496
  }
1385
1497
  #endif
1386
- if (backtraceSanitizerPath == NULL) {
1387
- backtraceSanitizerPath = "c++filt -n";
1388
- backtraceSanitizerUseShell = true;
1498
+ if (backtraceSanitizerCommand == NULL) {
1499
+ backtraceSanitizerCommand = "c++filt -n";
1389
1500
  backtraceSanitizerPassProgramInfo = false;
1390
1501
  }
1391
1502