passenger 3.9.2.beta → 4.0.0.rc4

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 (159) hide show
  1. data/.travis.yml +3 -0
  2. data/NEWS +77 -7
  3. data/README.md +3 -11
  4. data/bin/passenger-install-apache2-module +24 -20
  5. data/bin/passenger-install-nginx-module +25 -23
  6. data/build/agents.rb +11 -0
  7. data/build/apache2.rb +9 -5
  8. data/build/basics.rb +37 -30
  9. data/build/common_library.rb +4 -1
  10. data/build/cplusplus_support.rb +5 -5
  11. data/build/cxx_tests.rb +28 -8
  12. data/build/integration_tests.rb +6 -3
  13. data/build/nginx.rb +3 -3
  14. data/build/packaging.rb +95 -57
  15. data/build/ruby_extension.rb +34 -21
  16. data/build/ruby_tests.rb +4 -2
  17. data/build/test_basics.rb +1 -1
  18. data/dev/run_travis.sh +36 -1
  19. data/doc/Users guide Apache.html +425 -308
  20. data/doc/Users guide Apache.idmap.txt +78 -70
  21. data/doc/Users guide Apache.index.sqlite3 +0 -0
  22. data/doc/Users guide Apache.txt +33 -92
  23. data/doc/Users guide Nginx.html +519 -220
  24. data/doc/Users guide Nginx.idmap.txt +78 -60
  25. data/doc/Users guide Nginx.txt +115 -26
  26. data/doc/Users guide Standalone.html +8 -2
  27. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +1 -7
  28. data/doc/users_guide_snippets/installation.txt +167 -22
  29. data/doc/users_guide_snippets/rackup_specifications.txt +4 -0
  30. data/doc/users_guide_snippets/since_version.txt +1 -0
  31. data/doc/users_guide_snippets/support_information.txt +3 -7
  32. data/doc/users_guide_snippets/tips.txt +0 -24
  33. data/ext/apache2/Configuration.cpp +11 -33
  34. data/ext/apache2/Configuration.hpp +3 -18
  35. data/ext/apache2/DirectoryMapper.h +20 -70
  36. data/ext/apache2/Hooks.cpp +2 -2
  37. data/ext/common/AgentsStarter.cpp +0 -2
  38. data/ext/common/AgentsStarter.h +0 -1
  39. data/ext/common/AgentsStarter.hpp +1 -3
  40. data/ext/common/ApplicationPool2/AppTypes.cpp +74 -0
  41. data/ext/common/ApplicationPool2/AppTypes.h +202 -0
  42. data/ext/common/ApplicationPool2/Common.h +12 -10
  43. data/ext/common/ApplicationPool2/DirectSpawner.h +256 -0
  44. data/ext/common/ApplicationPool2/DummySpawner.h +90 -0
  45. data/ext/common/ApplicationPool2/Group.h +311 -94
  46. data/ext/common/ApplicationPool2/Implementation.cpp +405 -145
  47. data/ext/common/ApplicationPool2/Options.h +24 -26
  48. data/ext/common/ApplicationPool2/PipeWatcher.h +20 -13
  49. data/ext/common/ApplicationPool2/Pool.h +326 -183
  50. data/ext/common/ApplicationPool2/Process.h +205 -55
  51. data/ext/common/ApplicationPool2/README.md +1 -1
  52. data/ext/common/ApplicationPool2/Session.h +21 -10
  53. data/ext/common/ApplicationPool2/SmartSpawner.h +801 -0
  54. data/ext/common/ApplicationPool2/Spawner.h +141 -1149
  55. data/ext/common/ApplicationPool2/SpawnerFactory.h +132 -0
  56. data/ext/common/ApplicationPool2/SuperGroup.h +146 -223
  57. data/ext/common/Constants.h +4 -2
  58. data/ext/common/Exceptions.h +23 -1
  59. data/ext/common/Logging.cpp +17 -6
  60. data/ext/common/Logging.h +37 -7
  61. data/ext/common/ResourceLocator.h +1 -1
  62. data/ext/common/Utils.cpp +49 -1
  63. data/ext/common/Utils.h +13 -4
  64. data/ext/common/{AnsiColorConstants.h → Utils/AnsiColorConstants.h} +0 -0
  65. data/ext/common/{BCrypt.cpp → Utils/BCrypt.cpp} +0 -0
  66. data/ext/common/{BCrypt.h → Utils/BCrypt.h} +0 -0
  67. data/ext/common/{Blowfish.c → Utils/Blowfish.c} +0 -0
  68. data/ext/common/{Blowfish.h → Utils/Blowfish.h} +0 -0
  69. data/ext/common/Utils/CachedFileStat.hpp +27 -25
  70. data/ext/common/Utils/Curl.h +184 -0
  71. data/ext/common/{HttpConstants.h → Utils/HttpConstants.h} +3 -0
  72. data/ext/common/Utils/IOUtils.cpp +6 -2
  73. data/ext/common/{IniFile.h → Utils/IniFile.h} +0 -0
  74. data/ext/common/Utils/LargeFiles.cpp +30 -0
  75. data/ext/common/Utils/LargeFiles.h +40 -0
  76. data/ext/common/Utils/StrIntUtils.cpp +72 -8
  77. data/ext/common/Utils/StrIntUtils.h +24 -2
  78. data/ext/common/Utils/StringMap.h +12 -2
  79. data/ext/common/Utils/VariantMap.h +51 -2
  80. data/ext/common/Utils/jsoncpp.cpp +1 -1
  81. data/ext/common/agents/Base.cpp +147 -11
  82. data/ext/common/agents/HelperAgent/AgentOptions.h +14 -6
  83. data/ext/common/agents/HelperAgent/Main.cpp +79 -19
  84. data/ext/common/agents/HelperAgent/RequestHandler.h +36 -16
  85. data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -5
  86. data/ext/common/agents/LoggingAgent/Main.cpp +2 -4
  87. data/ext/common/agents/LoggingAgent/RemoteSender.h +18 -24
  88. data/ext/common/agents/SpawnPreparer.cpp +7 -0
  89. data/ext/common/agents/Watchdog/Main.cpp +96 -38
  90. data/ext/nginx/Configuration.c +26 -22
  91. data/ext/nginx/Configuration.h +4 -2
  92. data/ext/nginx/ContentHandler.c +23 -52
  93. data/ext/nginx/ContentHandler.h +5 -11
  94. data/ext/nginx/config +10 -3
  95. data/ext/nginx/ngx_http_passenger_module.c +21 -6
  96. data/ext/nginx/ngx_http_passenger_module.h +4 -1
  97. data/ext/oxt/dynamic_thread_group.hpp +9 -1
  98. data/ext/oxt/system_calls.cpp +2 -2
  99. data/ext/ruby/extconf.rb +2 -1
  100. data/helper-scripts/backtrace-sanitizer.rb +2 -0
  101. data/helper-scripts/wsgi-loader.py +54 -21
  102. data/lib/phusion_passenger.rb +5 -3
  103. data/lib/phusion_passenger/abstract_installer.rb +18 -41
  104. data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
  105. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  106. data/lib/phusion_passenger/common_library.rb +23 -3
  107. data/lib/phusion_passenger/debug_logging.rb +10 -3
  108. data/lib/phusion_passenger/packaging.rb +1 -0
  109. data/lib/phusion_passenger/platform_info.rb +113 -115
  110. data/lib/phusion_passenger/platform_info/compiler.rb +224 -134
  111. data/lib/phusion_passenger/platform_info/cxx_portability.rb +143 -0
  112. data/lib/phusion_passenger/platform_info/depcheck.rb +371 -0
  113. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +124 -0
  114. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +97 -0
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +39 -0
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +118 -0
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +137 -0
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +15 -0
  119. data/lib/phusion_passenger/platform_info/operating_system.rb +6 -5
  120. data/lib/phusion_passenger/platform_info/ruby.rb +45 -34
  121. data/lib/phusion_passenger/request_handler.rb +35 -22
  122. data/lib/phusion_passenger/request_handler/thread_handler.rb +5 -6
  123. data/lib/phusion_passenger/ruby_core_enhancements.rb +7 -1
  124. data/lib/phusion_passenger/standalone/runtime_installer.rb +43 -34
  125. data/lib/phusion_passenger/utils/robust_interruption.rb +34 -18
  126. data/passenger.gemspec +25 -0
  127. data/resources/templates/standalone/config.erb +3 -1
  128. data/test/config.json.travis +2 -2
  129. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +37 -5
  130. data/test/cxx/ApplicationPool2/PoolTest.cpp +143 -50
  131. data/test/cxx/ApplicationPool2/ProcessTest.cpp +8 -0
  132. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +28 -17
  133. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +31 -26
  134. data/test/cxx/RequestHandlerTest.cpp +17 -1
  135. data/test/cxx/UtilsTest.cpp +84 -10
  136. data/test/integration_tests/apache2_tests.rb +49 -163
  137. data/test/integration_tests/hello_world_wsgi_spec.rb +2 -2
  138. data/test/integration_tests/mycook_spec.rb +1 -1
  139. data/test/integration_tests/nginx_tests.rb +37 -19
  140. data/test/ruby/request_handler_spec.rb +1 -0
  141. data/test/ruby/spec_helper.rb +52 -1
  142. data/test/stub/nginx/nginx.conf.erb +2 -0
  143. data/test/stub/rack/start.rb +5 -0
  144. data/test/stub/rails3.0/Gemfile.lock +30 -30
  145. data/test/stub/rails3.1/Gemfile +1 -1
  146. data/test/stub/rails3.1/Gemfile.lock +3 -3
  147. data/test/stub/rails3.2/Gemfile +1 -1
  148. data/test/stub/rails3.2/Gemfile.lock +4 -4
  149. data/test/stub/rails_apps/2.3/mycook/app/controllers/welcome_controller.rb +1 -1
  150. data/test/stub/rails_apps/2.3/mycook/app/helpers/recipes_helper.rb +2 -0
  151. data/test/stub/rails_apps/2.3/mycook/app/helpers/test_helper.rb +2 -0
  152. data/test/stub/rails_apps/2.3/mycook/app/helpers/uploads_helper.rb +2 -0
  153. data/test/stub/rails_apps/2.3/mycook/app/helpers/welcome_helper.rb +2 -0
  154. data/test/support/nginx_controller.rb +2 -1
  155. metadata +160 -156
  156. data/build/gempackagetask.rb +0 -99
  157. data/build/packagetask.rb +0 -186
  158. data/ext/common/StringListCreator.h +0 -83
  159. data/lib/phusion_passenger/dependencies.rb +0 -657
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011 Phusion
3
+ * Copyright (c) 2011-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -30,6 +30,7 @@
30
30
  #include <utility>
31
31
 
32
32
  #include <StaticString.h>
33
+ #include <Utils/HashMap.h>
33
34
 
34
35
  namespace Passenger {
35
36
 
@@ -53,7 +54,7 @@ private:
53
54
  pair<StaticString, T> thePair;
54
55
  };
55
56
 
56
- typedef map<StaticString, Entry> InternalMap;
57
+ typedef HashMap<StaticString, Entry, StaticString::Hash> InternalMap;
57
58
  typedef typename InternalMap::iterator InternalIterator;
58
59
  typedef typename InternalMap::const_iterator InternalConstIterator;
59
60
  typedef typename InternalMap::value_type ValueType;
@@ -160,6 +161,15 @@ public:
160
161
  return it->second.thePair.second;
161
162
  }
162
163
  }
164
+
165
+ T get(const StaticString &key, const T &defaultValue) const {
166
+ InternalConstIterator it = store.find(key);
167
+ if (it == store.end()) {
168
+ return defaultValue;
169
+ } else {
170
+ return it->second.thePair.second;
171
+ }
172
+ }
163
173
 
164
174
  bool set(const StaticString &key, const T &value) {
165
175
  pair<InternalIterator, bool> result = store.insert(make_pair(key, Entry()));
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -168,37 +168,86 @@ public:
168
168
  store[name] = value;
169
169
  return *this;
170
170
  }
171
+
172
+ VariantMap &setDefault(const string &name, const string &value) {
173
+ if (store.find(name) == store.end()) {
174
+ store[name] = value;
175
+ }
176
+ return *this;
177
+ }
171
178
 
172
179
  VariantMap &setInt(const string &name, int value) {
173
180
  store[name] = toString(value);
174
181
  return *this;
175
182
  }
183
+
184
+ VariantMap &setDefaultInt(const string &name, int value) {
185
+ if (store.find(name) == store.end()) {
186
+ store[name] = toString(value);
187
+ }
188
+ return *this;
189
+ }
176
190
 
177
191
  VariantMap &setULL(const string &name, unsigned long long value) {
178
192
  store[name] = toString(value);
179
193
  return *this;
180
194
  }
195
+
196
+ VariantMap &setDefaultULL(const string &name, unsigned long long value) {
197
+ if (store.find(name) == store.end()) {
198
+ store[name] = toString(value);
199
+ }
200
+ return *this;
201
+ }
181
202
 
182
203
  VariantMap &setPid(const string &name, pid_t value) {
183
204
  store[name] = toString((unsigned long long) value);
184
205
  return *this;
185
206
  }
207
+
208
+ VariantMap &setDefaultPid(const string &name, pid_t value) {
209
+ if (store.find(name) == store.end()) {
210
+ store[name] = toString((unsigned long long) value);
211
+ }
212
+ return *this;
213
+ }
186
214
 
187
215
  VariantMap &setUid(const string &name, uid_t value) {
188
216
  store[name] = toString((long long) value);
189
217
  return *this;
190
218
  }
219
+
220
+ VariantMap &setDefaultUid(const string &name, uid_t value) {
221
+ if (store.find(name) == store.end()) {
222
+ store[name] = toString((unsigned long long) value);
223
+ }
224
+ return *this;
225
+ }
191
226
 
192
227
  VariantMap &setGid(const string &name, gid_t value) {
193
228
  store[name] = toString((long long) value);
194
229
  return *this;
195
230
  }
231
+
232
+ VariantMap &setDefaultGid(const string &name, gid_t value) {
233
+ if (store.find(name) == store.end()) {
234
+ store[name] = toString((unsigned long long) value);
235
+ }
236
+ return *this;
237
+ }
196
238
 
197
239
  VariantMap &setBool(const string &name, bool value) {
198
240
  store[name] = value ? "true" : "false";
199
241
  return *this;
200
242
  }
201
-
243
+
244
+ VariantMap &setDefaultBool(const string &name, bool value) {
245
+ if (store.find(name) == store.end()) {
246
+ store[name] = value ? "true" : "false";
247
+ }
248
+ return *this;
249
+ }
250
+
202
251
  const string &get(const string &name, bool required = true) const {
203
252
  map<string, string>::const_iterator it = store.find(name);
204
253
  if (it == store.end()) {
@@ -3461,7 +3461,7 @@ std::string valueToString( double value )
3461
3461
  #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
3462
3462
  sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
3463
3463
  #else
3464
- sprintf(buffer, "%#.16g", value);
3464
+ snprintf(buffer, sizeof(buffer), "%#.16g", value);
3465
3465
  #endif
3466
3466
  char* ch = buffer + strlen(buffer) - 1;
3467
3467
  if (*ch != '0') return buffer; // nothing to truncate, so save time
@@ -33,11 +33,13 @@
33
33
  #include <sys/select.h>
34
34
  #ifdef __linux__
35
35
  #include <sys/syscall.h>
36
+ #include <features.h>
36
37
  #endif
37
38
  #include <cstdio>
38
39
  #include <cstdlib>
39
40
  #include <cstring>
40
41
  #include <cerrno>
42
+ #include <cassert>
41
43
  #include <fcntl.h>
42
44
  #include <poll.h>
43
45
  #include <unistd.h>
@@ -96,7 +98,8 @@ static bool stopOnAbort = false;
96
98
  static char *alternativeStack;
97
99
  static unsigned int alternativeStackSize;
98
100
 
99
- static unsigned int randomSeed;
101
+ static volatile unsigned int abortHandlerCalled = 0;
102
+ static unsigned int randomSeed = 0;
100
103
  static const char *argv0 = NULL;
101
104
  static const char *backtraceSanitizerPath = NULL;
102
105
  static bool backtraceSanitizerUseShell = false;
@@ -104,6 +107,14 @@ static bool backtraceSanitizerPassProgramInfo = true;
104
107
  static DiagnosticsDumper customDiagnosticsDumper = NULL;
105
108
  static void *customDiagnosticsDumperUserData;
106
109
 
110
+ // If assert() failed, its information is stored here.
111
+ static struct {
112
+ const char *filename;
113
+ const char *function; // May be NULL.
114
+ const char *expression;
115
+ unsigned int line;
116
+ } lastAssertionFailure;
117
+
107
118
 
108
119
  static void
109
120
  ignoreSigpipe() {
@@ -254,6 +265,9 @@ appendSignalName(char *buf, int signo) {
254
265
  case SIGFPE:
255
266
  buf = appendText(buf, "SIGFPE");
256
267
  break;
268
+ case SIGILL:
269
+ buf = appendText(buf, "SIGILL");
270
+ break;
257
271
  default:
258
272
  return appendULL(buf, (unsigned long long) signo);
259
273
  }
@@ -454,10 +468,12 @@ dumpWithCrashWatch(AbortHandlerState &state) {
454
468
  if (pipe(p) == -1) {
455
469
  int e = errno;
456
470
  end = state.messageBuf;
457
- end = appendText(end, "Could not dump diagnostics: pipe() failed with errno=");
471
+ end = appendText(end, "Could not dump diagnostics through backtrace sanitizer: pipe() failed with errno=");
458
472
  end = appendULL(end, e);
459
473
  end = appendText(end, "\n");
474
+ end = appendText(end, "Falling back to writing to stderr directly...\n");
460
475
  write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
476
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
461
477
  return;
462
478
  }
463
479
 
@@ -505,12 +521,29 @@ dumpWithCrashWatch(AbortHandlerState &state) {
505
521
  } else if (pid == -1) {
506
522
  close(p[0]);
507
523
  close(p[1]);
524
+ int e = errno;
525
+ end = state.messageBuf;
526
+ end = appendText(end, "Could not dump diagnostics through backtrace sanitizer: fork() failed with errno=");
527
+ end = appendULL(end, e);
528
+ end = appendText(end, "\n");
529
+ end = appendText(end, "Falling back to writing to stderr directly...\n");
530
+ write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
531
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
508
532
 
509
533
  } else {
534
+ int status = -1;
535
+
510
536
  close(p[0]);
511
537
  backtrace_symbols_fd(backtraceStore, frames, p[1]);
512
538
  close(p[1]);
513
- waitpid(pid, NULL, 0);
539
+ if (waitpid(pid, &status, 0) == -1 || status != 0) {
540
+ end = state.messageBuf;
541
+ end = appendText(end, "ERROR: cannot execute '");
542
+ end = appendText(end, backtraceSanitizerPath);
543
+ end = appendText(end, "' for sanitizing the backtrace, writing to stderr directly...\n");
544
+ write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
545
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
546
+ }
514
547
  }
515
548
 
516
549
  } else {
@@ -524,12 +557,15 @@ runCustomDiagnosticsDumper(AbortHandlerState &state, void *userData) {
524
557
  customDiagnosticsDumper(customDiagnosticsDumperUserData);
525
558
  }
526
559
 
560
+ // This function is performed in a child process.
527
561
  static void
528
562
  dumpDiagnostics(AbortHandlerState &state) {
529
563
  char *messageBuf = state.messageBuf;
564
+ char *end;
565
+ pid_t pid;
530
566
 
531
- // Dump human-readable time string.
532
- pid_t pid = asyncFork();
567
+ // Dump human-readable time string and string.
568
+ pid = asyncFork();
533
569
  if (pid == 0) {
534
570
  execlp("date", "date", (const char * const) 0);
535
571
  _exit(1);
@@ -539,10 +575,45 @@ dumpDiagnostics(AbortHandlerState &state) {
539
575
  waitpid(pid, NULL, 0);
540
576
  }
541
577
 
578
+ // Dump system uname.
579
+ pid = asyncFork();
580
+ if (pid == 0) {
581
+ execlp("uname", "uname", "-mprsv", (const char * const) 0);
582
+ _exit(1);
583
+ } else if (pid == -1) {
584
+ safePrintErr("ERROR: Could not fork a process to dump the uname!\n");
585
+ } else {
586
+ waitpid(pid, NULL, 0);
587
+ }
588
+
589
+ end = messageBuf;
590
+ end = appendText(end, state.messagePrefix);
591
+ end = appendText(end, " ] Phusion Passenger version: " PASSENGER_VERSION "\n");
592
+ write(STDERR_FILENO, messageBuf, end - messageBuf);
593
+
594
+ if (lastAssertionFailure.filename != NULL) {
595
+ end = messageBuf;
596
+ end = appendText(end, state.messagePrefix);
597
+ end = appendText(end, " ] Last assertion failure: (");
598
+ end = appendText(end, lastAssertionFailure.expression);
599
+ end = appendText(end, "), ");
600
+ if (lastAssertionFailure.function != NULL) {
601
+ end = appendText(end, "function ");
602
+ end = appendText(end, lastAssertionFailure.function);
603
+ end = appendText(end, ", ");
604
+ }
605
+ end = appendText(end, "file ");
606
+ end = appendText(end, lastAssertionFailure.filename);
607
+ end = appendText(end, ", line ");
608
+ end = appendULL(end, lastAssertionFailure.line);
609
+ end = appendText(end, ".\n");
610
+ write(STDERR_FILENO, messageBuf, end - messageBuf);
611
+ }
612
+
542
613
  // It is important that writing the message and the backtrace are two
543
614
  // seperate operations because it's not entirely clear whether the
544
615
  // latter is async signal safe and thus can crash.
545
- char *end = messageBuf;
616
+ end = messageBuf;
546
617
  end = appendText(end, state.messagePrefix);
547
618
  #ifdef LIBC_HAS_BACKTRACE_FUNC
548
619
  end = appendText(end, " ] libc backtrace available!\n");
@@ -648,6 +719,40 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
648
719
  time_t t = time(NULL);
649
720
  char crashLogFile[256];
650
721
 
722
+ abortHandlerCalled++;
723
+ if (abortHandlerCalled > 1) {
724
+ // The abort handler itself crashed!
725
+ char *end = state.messageBuf;
726
+ end = appendText(end, "[ origpid=");
727
+ end = appendULL(end, (unsigned long long) state.pid);
728
+ end = appendText(end, ", pid=");
729
+ end = appendULL(end, (unsigned long long) getpid());
730
+ end = appendText(end, ", timestamp=");
731
+ end = appendULL(end, (unsigned long long) t);
732
+ if (abortHandlerCalled == 2) {
733
+ // This is the first time it crashed.
734
+ end = appendText(end, " ] Abort handler crashed! signo=");
735
+ end = appendSignalName(end, state.signo);
736
+ end = appendText(end, ", reason=");
737
+ end = appendSignalReason(end, state.info);
738
+ end = appendText(end, "\n");
739
+ write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
740
+ // Run default signal handler.
741
+ raise(signo);
742
+ } else {
743
+ // This is the second time it crashed, meaning it failed to
744
+ // invoke the default signal handler to abort the process!
745
+ end = appendText(end, " ] Abort handler crashed again! Force exiting this time. signo=");
746
+ end = appendSignalName(end, state.signo);
747
+ end = appendText(end, ", reason=");
748
+ end = appendSignalReason(end, state.info);
749
+ end = appendText(end, "\n");
750
+ write(STDERR_FILENO, state.messageBuf, end - state.messageBuf);
751
+ _exit(1);
752
+ }
753
+ return;
754
+ }
755
+
651
756
  /* We want to dump the entire crash log to both stderr and a log file.
652
757
  * We use 'tee' for this.
653
758
  */
@@ -739,6 +844,11 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
739
844
 
740
845
  child = asyncFork();
741
846
  if (child == 0) {
847
+ // OS X: for some reason the SIGPIPE handler may be reset to default after forking.
848
+ // Later in this program we're going to pipe backtrace_symbols_fd() into the backtrace
849
+ // sanitizer, which may fail, and we don't want the diagnostics process to crash
850
+ // with SIGPIPE as a result, so we ignore SIGPIPE again.
851
+ ignoreSigpipe();
742
852
  dumpDiagnostics(state);
743
853
  // The child process may or may or may not resume the original process.
744
854
  // We do it ourselves just to be sure.
@@ -778,7 +888,27 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
778
888
  raise(signo);
779
889
  }
780
890
 
781
- #ifdef __APPLE__
891
+ /*
892
+ * Override assert() to add more features and to fix bugs. We save the information
893
+ * of the last assertion failure in a global variable so that we can print it
894
+ * to the crash diagnostics report.
895
+ */
896
+ #if defined(__GLIBC__)
897
+ extern "C" __attribute__ ((__noreturn__))
898
+ void
899
+ __assert_fail(__const char *__assertion, __const char *__file,
900
+ unsigned int __line, __const char *__function)
901
+ {
902
+ lastAssertionFailure.filename = __file;
903
+ lastAssertionFailure.line = __line;
904
+ lastAssertionFailure.function = __function;
905
+ lastAssertionFailure.expression = __assertion;
906
+ fprintf(stderr, "Assertion failed! %s:%u: %s: %s\n", __file, __line, __function, __assertion);
907
+ fflush(stderr);
908
+ abort();
909
+ }
910
+
911
+ #elif defined(__APPLE__)
782
912
  /* On OS X, raise() and abort() unfortunately send SIGABRT to the main thread,
783
913
  * causing the original backtrace to be lost in the signal handler.
784
914
  * We work around this for anything in the same linkage unit by just definin
@@ -787,13 +917,17 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
787
917
 
788
918
  #include <pthread.h>
789
919
 
790
- static int
920
+ extern "C" int
791
921
  raise(int sig) {
792
922
  return pthread_kill(pthread_self(), sig);
793
923
  }
794
924
 
795
- void
925
+ extern "C" void
796
926
  __assert_rtn(const char *func, const char *file, int line, const char *expr) {
927
+ lastAssertionFailure.filename = file;
928
+ lastAssertionFailure.line = line;
929
+ lastAssertionFailure.function = func;
930
+ lastAssertionFailure.expression = expr;
797
931
  if (func) {
798
932
  fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n",
799
933
  expr, func, file, line);
@@ -801,10 +935,11 @@ abortHandler(int signo, siginfo_t *info, void *ctx) {
801
935
  fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n",
802
936
  expr, file, line);
803
937
  }
938
+ fflush(stderr);
804
939
  abort();
805
940
  }
806
941
 
807
- void
942
+ extern "C" void
808
943
  abort() {
809
944
  sigset_t set;
810
945
  sigemptyset(&set);
@@ -1254,7 +1389,8 @@ initializeAgent(int argc, char *argv[], const char *processName) {
1254
1389
  backtraceSanitizerPassProgramInfo = false;
1255
1390
  }
1256
1391
 
1257
- setLogLevel(options.getInt("log_level", false, 0));
1392
+ options.setDefaultInt("log_level", DEFAULT_LOG_LEVEL);
1393
+ setLogLevel(options.getInt("log_level"));
1258
1394
  if (!options.get("debug_log_file", false).empty()) {
1259
1395
  if (strcmp(processName, "PassengerWatchdog") == 0) {
1260
1396
  /* Have the watchdog set STDOUT and STDERR to the debug
@@ -53,25 +53,33 @@ struct AgentOptions {
53
53
  string loggingAgentPassword;
54
54
  string prestartUrls;
55
55
 
56
+ string requestSocketLink;
57
+
56
58
  AgentOptions() { }
57
59
 
58
60
  AgentOptions(const VariantMap &options) {
59
- webServerPid = options.getPid("web_server_pid");
60
- tempDir = options.get("temp_dir");
61
+ // Required options for which a default is already set by the Watchdog.
62
+ passengerRoot = options.get("passenger_root");
63
+ tempDir = options.get("temp_dir");
61
64
  userSwitching = options.getBool("user_switching");
65
+ rubyCommand = options.get("ruby");
62
66
  defaultUser = options.get("default_user");
63
67
  defaultGroup = options.get("default_group");
64
- passengerRoot = options.get("passenger_root");
65
- rubyCommand = options.get("ruby");
66
- generationNumber = options.getInt("generation_number");
67
68
  maxPoolSize = options.getInt("max_pool_size");
68
69
  maxInstancesPerApp = options.getInt("max_instances_per_app");
69
70
  poolIdleTime = options.getInt("pool_idle_time");
71
+
72
+ // Required options only set by the Watchdog.
73
+ webServerPid = options.getPid("web_server_pid");
74
+ generationNumber = options.getInt("generation_number");
70
75
  requestSocketPassword = Base64::decode(options.get("request_socket_password"));
71
76
  messageSocketPassword = Base64::decode(options.get("message_socket_password"));
72
77
  loggingAgentAddress = options.get("logging_agent_address");
73
78
  loggingAgentPassword = options.get("logging_agent_password");
74
- prestartUrls = options.get("prestart_urls");
79
+
80
+ // Optional options.
81
+ prestartUrls = options.get("prestart_urls", false, "");
82
+ requestSocketLink = options.get("request_socket_link", false);
75
83
  }
76
84
  };
77
85