passenger 5.1.10 → 5.1.11

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -0
  3. data/Rakefile +20 -17
  4. data/bin/passenger-install-apache2-module +14 -11
  5. data/build/agent.rb +45 -18
  6. data/build/apache2.rb +32 -16
  7. data/build/basics.rb +29 -40
  8. data/build/common_library.rb +70 -54
  9. data/build/cxx_tests.rb +34 -43
  10. data/build/integration_tests.rb +10 -10
  11. data/build/misc.rb +6 -6
  12. data/build/node_tests.rb +1 -2
  13. data/build/oxt_tests.rb +7 -5
  14. data/build/packaging.rb +11 -441
  15. data/build/ruby_extension.rb +1 -1
  16. data/build/ruby_tests.rb +1 -2
  17. data/build/support/cplusplus.rb +6 -5
  18. data/build/support/cxx_dependency_map.rb +357 -833
  19. data/build/support/general.rb +23 -1
  20. data/build/test_basics.rb +3 -28
  21. data/dev/ci/tests/rpm/Jenkinsfile +68 -0
  22. data/dev/ci/tests/rpm/run +63 -0
  23. data/dev/ci/tests/source-packaging/run +1 -1
  24. data/dev/ci/tests/source-packaging/setup +1 -1
  25. data/doc/{Packaging.txt.md → Packaging.md} +0 -0
  26. data/resources/templates/apache2/deployment_example.txt.erb +2 -2
  27. data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
  28. data/resources/templates/nginx/deployment_example.txt.erb +1 -1
  29. data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
  30. data/resources/templates/standalone/server.erb +2 -2
  31. data/src/agent/AgentMain.cpp +0 -4
  32. data/src/agent/Core/CoreMain.cpp +88 -5
  33. data/src/agent/Core/SpawningKit/Spawner.h +2 -1
  34. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
  35. data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
  36. data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
  37. data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
  38. data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
  39. data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
  40. data/src/agent/Shared/Fundamentals/Utils.h +46 -0
  41. data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
  42. data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
  43. data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
  44. data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
  45. data/src/apache2_module/Hooks.cpp +4 -1
  46. data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
  47. data/src/cxx_supportlib/Constants.h +1 -2
  48. data/src/cxx_supportlib/Crypto.cpp +2 -1
  49. data/src/cxx_supportlib/Hooks.h +16 -37
  50. data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
  51. data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
  52. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
  53. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
  54. data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
  55. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
  56. data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
  57. data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
  58. data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
  59. data/src/cxx_supportlib/Utils.cpp +41 -561
  60. data/src/cxx_supportlib/Utils.h +0 -68
  61. data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
  62. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
  63. data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
  64. data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
  65. data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
  66. data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
  67. data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
  68. data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
  69. data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
  70. data/src/nginx_module/CacheLocationConfig.c +0 -75
  71. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
  72. data/src/nginx_module/Configuration.c +0 -1
  73. data/src/nginx_module/Configuration.h +0 -1
  74. data/src/nginx_module/ConfigurationCommands.c +1 -1
  75. data/src/nginx_module/ContentHandler.c +0 -1
  76. data/src/nginx_module/ContentHandler.h +0 -1
  77. data/src/nginx_module/CreateLocationConfig.c +0 -5
  78. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
  79. data/src/nginx_module/LocationConfig.h +0 -4
  80. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
  81. data/src/nginx_module/MergeLocationConfig.c +0 -12
  82. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
  83. data/src/nginx_module/ngx_http_passenger_module.h +0 -1
  84. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  85. data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
  86. data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
  87. data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
  88. data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
  89. data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
  90. data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
  91. data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
  92. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
  93. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
  94. data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
  95. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
  96. data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
  97. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
  98. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
  99. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
  100. data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
  101. data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
  102. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
  103. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
  104. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
  105. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
  106. data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
  107. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
  108. metadata +19 -97
  109. data/build/documentation.rb +0 -70
  110. data/doc/CloudLicensingConfiguration.html +0 -172
  111. data/doc/CloudLicensingConfiguration.txt.md +0 -3
  112. data/doc/Packaging.html +0 -488
  113. data/doc/Security of user switching support.idmap.txt +0 -34
  114. data/doc/Security of user switching support.txt +0 -197
  115. data/doc/ServerOptimizationGuide.html +0 -172
  116. data/doc/ServerOptimizationGuide.txt.md +0 -3
  117. data/doc/images/by_sa.png +0 -0
  118. data/doc/images/cloud_licensing_batch_job.png +0 -0
  119. data/doc/images/code_walkthrough.jpg +0 -0
  120. data/doc/images/direct_spawning.png +0 -0
  121. data/doc/images/direct_spawning.svg +0 -251
  122. data/doc/images/glyphicons-halflings-white.png +0 -0
  123. data/doc/images/glyphicons-halflings.png +0 -0
  124. data/doc/images/icons/README +0 -5
  125. data/doc/images/icons/callouts/1.png +0 -0
  126. data/doc/images/icons/callouts/10.png +0 -0
  127. data/doc/images/icons/callouts/11.png +0 -0
  128. data/doc/images/icons/callouts/12.png +0 -0
  129. data/doc/images/icons/callouts/13.png +0 -0
  130. data/doc/images/icons/callouts/14.png +0 -0
  131. data/doc/images/icons/callouts/15.png +0 -0
  132. data/doc/images/icons/callouts/2.png +0 -0
  133. data/doc/images/icons/callouts/3.png +0 -0
  134. data/doc/images/icons/callouts/4.png +0 -0
  135. data/doc/images/icons/callouts/5.png +0 -0
  136. data/doc/images/icons/callouts/6.png +0 -0
  137. data/doc/images/icons/callouts/7.png +0 -0
  138. data/doc/images/icons/callouts/8.png +0 -0
  139. data/doc/images/icons/callouts/9.png +0 -0
  140. data/doc/images/icons/caution.png +0 -0
  141. data/doc/images/icons/example.png +0 -0
  142. data/doc/images/icons/home.png +0 -0
  143. data/doc/images/icons/important.png +0 -0
  144. data/doc/images/icons/next.png +0 -0
  145. data/doc/images/icons/note.png +0 -0
  146. data/doc/images/icons/prev.png +0 -0
  147. data/doc/images/icons/tip.png +0 -0
  148. data/doc/images/icons/up.png +0 -0
  149. data/doc/images/icons/warning.png +0 -0
  150. data/doc/images/many_web_framework_protocols.png +0 -0
  151. data/doc/images/passenger_architecture.png +0 -0
  152. data/doc/images/passenger_architecture.svg +0 -385
  153. data/doc/images/passenger_architecture_overview.png +0 -0
  154. data/doc/images/passenger_core_architecture.png +0 -0
  155. data/doc/images/passenger_nodejs_architecture.svg +0 -558
  156. data/doc/images/phusion_banner.png +0 -0
  157. data/doc/images/rack.png +0 -0
  158. data/doc/images/smart_spawning.png +0 -0
  159. data/doc/images/smart_spawning.svg +0 -323
  160. data/doc/images/spawn_server_architecture.png +0 -0
  161. data/doc/images/spawn_server_architecture.svg +0 -655
  162. data/doc/images/spawning_preparation_work.png +0 -0
  163. data/doc/images/startup_sequence.png +0 -0
  164. data/doc/images/typical_isolated_web_application.png +0 -0
  165. data/doc/images/typical_isolated_web_application.svg +0 -213
  166. data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
  167. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
  168. data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
  169. data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
  170. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
  171. data/doc/users_guide_snippets/deployment_basics.txt +0 -37
  172. data/doc/users_guide_snippets/enterprise_only.txt +0 -1
  173. data/doc/users_guide_snippets/environment_variables.txt +0 -44
  174. data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
  175. data/doc/users_guide_snippets/installation.txt +0 -228
  176. data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
  177. data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
  178. data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
  179. data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
  180. data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
  181. data/doc/users_guide_snippets/since_version.txt +0 -1
  182. data/doc/users_guide_snippets/support_information.txt +0 -8
  183. data/doc/users_guide_snippets/tips.txt +0 -302
  184. data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
  185. data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
  186. data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
  187. data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
  188. data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
  189. data/src/agent/Shared/Base.cpp +0 -1678
  190. data/src/agent/UstRouter/ApiServer.h +0 -292
  191. data/src/agent/UstRouter/Client.h +0 -112
  192. data/src/agent/UstRouter/Controller.h +0 -1309
  193. data/src/agent/UstRouter/LogSink.h +0 -145
  194. data/src/agent/UstRouter/OptionParser.h +0 -180
  195. data/src/agent/UstRouter/RemoteSender.h +0 -853
  196. data/src/agent/UstRouter/RemoteSink.h +0 -145
  197. data/src/agent/UstRouter/Transaction.h +0 -278
  198. data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
  199. data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
  200. data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -721,7 +721,6 @@ protected:
721
721
  prepareChroot(info, options);
722
722
  info.userSwitching = prepareUserSwitching(options);
723
723
  prepareSwitchingWorkingDirectory(info, options);
724
- inferApplicationInfo(info);
725
724
  return info;
726
725
  }
727
726
 
@@ -775,6 +774,7 @@ protected:
775
774
  assert(info.appRootPathsInsideChroot.back() == info.appRootInsideChroot);
776
775
  }
777
776
 
777
+ #ifdef false
778
778
  void inferApplicationInfo(SpawnPreparationInfo &info) const {
779
779
  info.codeRevision = readFromRevisionFile(info);
780
780
  if (info.codeRevision.empty()) {
@@ -817,6 +817,7 @@ protected:
817
817
  return string();
818
818
  }
819
819
  }
820
+ #endif
820
821
 
821
822
  bool shouldLoadShellEnvvars(const Options &options, const SpawnPreparationInfo &preparation) const {
822
823
  if (options.loadShellEnvvars) {
@@ -0,0 +1,1109 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2010-2017 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+ #include <Shared/Fundamentals/AbortHandler.h>
28
+
29
+ #include <boost/cstdint.hpp>
30
+ #include <sys/types.h>
31
+ #include <sys/stat.h>
32
+ #include <sys/select.h>
33
+ #include <cstdio>
34
+ #include <cstdlib>
35
+ #include <cstddef>
36
+ #include <cstring>
37
+ #include <cerrno>
38
+ #include <cassert>
39
+ #include <fcntl.h>
40
+ #include <poll.h>
41
+ #include <unistd.h>
42
+ #include <signal.h>
43
+ #include <libgen.h>
44
+
45
+ #ifdef __linux__
46
+ #include <sys/syscall.h>
47
+ #include <features.h>
48
+ #endif
49
+ #if defined(__APPLE__) || defined(__GNU_LIBRARY__)
50
+ #define LIBC_HAS_BACKTRACE_FUNC
51
+ #endif
52
+ #ifdef LIBC_HAS_BACKTRACE_FUNC
53
+ #include <execinfo.h>
54
+ #endif
55
+
56
+ #include <Shared/Fundamentals/AbortHandler.h>
57
+ #include <Shared/Fundamentals/Utils.h>
58
+ #include <Constants.h>
59
+ #include <LoggingKit/LoggingKit.h>
60
+ #include <LoggingKit/Context.h>
61
+ #include <ResourceLocator.h>
62
+ #include <ProcessManagement/Utils.h>
63
+ #include <Utils.h>
64
+ #include <Utils/AsyncSignalSafeUtils.h>
65
+
66
+ namespace Passenger {
67
+ namespace Agent {
68
+ namespace Fundamentals {
69
+
70
+ using namespace std;
71
+ namespace ASSU = AsyncSignalSafeUtils;
72
+
73
+
74
+ struct AbortHandlerContext {
75
+ const AbortHandlerConfig *config;
76
+ char *installSpec;
77
+ char *rubyLibDir;
78
+ char *crashWatchCommand;
79
+ char *backtraceSanitizerCommand;
80
+ bool backtraceSanitizerPassProgramInfo;
81
+
82
+ int emergencyPipe1[2];
83
+ int emergencyPipe2[2];
84
+
85
+ char *alternativeStack;
86
+
87
+ volatile sig_atomic_t callCount;
88
+ };
89
+
90
+ struct AbortHandlerWorkingState {
91
+ pid_t pid;
92
+ int signo;
93
+ siginfo_t *info;
94
+ char messagePrefix[32];
95
+ char messageBuf[1024];
96
+ };
97
+
98
+ typedef void (*Callback)(AbortHandlerWorkingState &state, void *userData);
99
+
100
+
101
+ #define IGNORE_SYSCALL_RESULT(code) \
102
+ do { \
103
+ int _ret = code; \
104
+ (void) _ret; \
105
+ } while (false)
106
+
107
+
108
+ static AbortHandlerContext *ctx = NULL;
109
+ static const char digits[] = "0123456789";
110
+ static const char hex_chars[] = "0123456789abcdef";
111
+
112
+
113
+ static void
114
+ write_nowarn(int fd, const void *buf, size_t n) {
115
+ ASSU::writeNoWarn(fd, buf, n);
116
+ }
117
+
118
+ static char *
119
+ appendSignalName(char *pos, const char *end, int signo) {
120
+ switch (signo) {
121
+ case SIGABRT:
122
+ pos = ASSU::appendData(pos, end, "SIGABRT");
123
+ break;
124
+ case SIGSEGV:
125
+ pos = ASSU::appendData(pos, end, "SIGSEGV");
126
+ break;
127
+ case SIGBUS:
128
+ pos = ASSU::appendData(pos, end, "SIGBUS");
129
+ break;
130
+ case SIGFPE:
131
+ pos = ASSU::appendData(pos, end, "SIGFPE");
132
+ break;
133
+ case SIGILL:
134
+ pos = ASSU::appendData(pos, end, "SIGILL");
135
+ break;
136
+ default:
137
+ return ASSU::appendInteger<int, 10>(pos, end, signo);
138
+ }
139
+ pos = ASSU::appendData(pos, end, "(");
140
+ pos = ASSU::appendInteger<int, 10>(pos, end, signo);
141
+ pos = ASSU::appendData(pos, end, ")");
142
+ return pos;
143
+ }
144
+
145
+ #define SI_CODE_HANDLER(name) \
146
+ case name: \
147
+ buf = ASSU::appendData(buf, end, #name); \
148
+ break
149
+
150
+ // Must be async signal safe.
151
+ static char *
152
+ appendSignalReason(char *buf, const char *end, siginfo_t *info) {
153
+ bool handled = true;
154
+
155
+ switch (info->si_code) {
156
+ SI_CODE_HANDLER(SI_USER);
157
+ #ifdef SI_KERNEL
158
+ SI_CODE_HANDLER(SI_KERNEL);
159
+ #endif
160
+ SI_CODE_HANDLER(SI_QUEUE);
161
+ SI_CODE_HANDLER(SI_TIMER);
162
+ #ifdef SI_ASYNCIO
163
+ SI_CODE_HANDLER(SI_ASYNCIO);
164
+ #endif
165
+ #ifdef SI_MESGQ
166
+ SI_CODE_HANDLER(SI_MESGQ);
167
+ #endif
168
+ #ifdef SI_SIGIO
169
+ SI_CODE_HANDLER(SI_SIGIO);
170
+ #endif
171
+ #ifdef SI_TKILL
172
+ SI_CODE_HANDLER(SI_TKILL);
173
+ #endif
174
+ default:
175
+ switch (info->si_signo) {
176
+ case SIGSEGV:
177
+ switch (info->si_code) {
178
+ #ifdef SEGV_MAPERR
179
+ SI_CODE_HANDLER(SEGV_MAPERR);
180
+ #endif
181
+ #ifdef SEGV_ACCERR
182
+ SI_CODE_HANDLER(SEGV_ACCERR);
183
+ #endif
184
+ default:
185
+ handled = false;
186
+ break;
187
+ }
188
+ break;
189
+ case SIGBUS:
190
+ switch (info->si_code) {
191
+ #ifdef BUS_ADRALN
192
+ SI_CODE_HANDLER(BUS_ADRALN);
193
+ #endif
194
+ #ifdef BUS_ADRERR
195
+ SI_CODE_HANDLER(BUS_ADRERR);
196
+ #endif
197
+ #ifdef BUS_OBJERR
198
+ SI_CODE_HANDLER(BUS_OBJERR);
199
+ #endif
200
+ default:
201
+ handled = false;
202
+ break;
203
+ }
204
+ break;
205
+ default:
206
+ handled = false;
207
+ break;
208
+ }
209
+ if (!handled) {
210
+ buf = ASSU::appendData(buf, end, "#");
211
+ buf = ASSU::appendInteger<int, 10>(buf, end, info->si_code);
212
+ }
213
+ break;
214
+ }
215
+
216
+ if (info->si_code <= 0) {
217
+ buf = ASSU::appendData(buf, end, ", signal sent by PID ");
218
+ buf = ASSU::appendInteger<pid_t, 10>(buf, end, info->si_pid);
219
+ buf = ASSU::appendData(buf, end, " with UID ");
220
+ buf = ASSU::appendInteger<uid_t, 10>(buf, end, info->si_uid);
221
+ }
222
+
223
+ buf = ASSU::appendData(buf, end, ", si_addr=0x");
224
+ buf = ASSU::appendInteger<boost::uintptr_t, 16>(buf, end, (boost::uintptr_t) info->si_addr);
225
+
226
+ return buf;
227
+ }
228
+
229
+ static int
230
+ runInSubprocessWithTimeLimit(AbortHandlerWorkingState &state, Callback callback, void *userData, int timeLimit) {
231
+ char *pos;
232
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
233
+ pid_t child;
234
+ int p[2], e;
235
+
236
+ if (pipe(p) == -1) {
237
+ e = errno;
238
+ pos = state.messageBuf;
239
+ pos = ASSU::appendData(pos, end, "Could not create subprocess: pipe() failed: ");
240
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
241
+ pos = ASSU::appendData(pos, end, " (errno=");
242
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
243
+ pos = ASSU::appendData(pos, end, ")\n");
244
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
245
+ return -1;
246
+ }
247
+
248
+ child = asyncFork();
249
+ if (child == 0) {
250
+ close(p[0]);
251
+ callback(state, userData);
252
+ _exit(0);
253
+ return -1;
254
+
255
+ } else if (child == -1) {
256
+ e = errno;
257
+ close(p[0]);
258
+ close(p[1]);
259
+ pos = state.messageBuf;
260
+ pos = ASSU::appendData(pos, end, "Could not create subprocess: fork() failed: ");
261
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
262
+ pos = ASSU::appendData(pos, end, " (errno=");
263
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
264
+ pos = ASSU::appendData(pos, end, ")\n");
265
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
266
+ return -1;
267
+
268
+ } else {
269
+ int status;
270
+ close(p[1]);
271
+
272
+ // We give the child process a time limit. If it doesn't succeed in
273
+ // exiting within the time limit, we assume that it has frozen
274
+ // and we kill it.
275
+ struct pollfd fd;
276
+ fd.fd = p[0];
277
+ fd.events = POLLIN | POLLHUP | POLLERR;
278
+ if (poll(&fd, 1, timeLimit) <= 0) {
279
+ kill(child, SIGKILL);
280
+ ASSU::printError("Could not run child process: it did not exit in time\n");
281
+ }
282
+ close(p[0]);
283
+ if (waitpid(child, &status, 0) == child) {
284
+ return status;
285
+ } else {
286
+ return -1;
287
+ }
288
+ }
289
+ }
290
+
291
+ static void
292
+ dumpFileDescriptorInfoWithLsof(AbortHandlerWorkingState &state, void *userData) {
293
+ char *pos = state.messageBuf;
294
+ const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
295
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
296
+ *pos = '\0';
297
+
298
+ closeAllFileDescriptors(2, true);
299
+
300
+ execlp("lsof", "lsof", "-p", state.messageBuf, "-nP", (const char * const) 0);
301
+
302
+ const char *command[] = { "lsof", NULL };
303
+ printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
304
+ _exit(1);
305
+ }
306
+
307
+ static void
308
+ dumpFileDescriptorInfoWithLs(AbortHandlerWorkingState &state) {
309
+ pid_t pid;
310
+ int status;
311
+
312
+ pid = asyncFork();
313
+ if (pid == 0) {
314
+ closeAllFileDescriptors(2, true);
315
+ // The '-v' is for natural sorting on Linux. On BSD -v means something else but it's harmless.
316
+ execlp("ls", "ls", "-lv", state.messageBuf, (const char * const) 0);
317
+
318
+ const char *command[] = { "ls", NULL };
319
+ printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
320
+ _exit(1);
321
+ } else if (pid == -1) {
322
+ ASSU::printError("ERROR: Could not fork a process to dump file descriptor information!\n");
323
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
324
+ ASSU::printError("ERROR: Could not run 'ls' to dump file descriptor information!\n");
325
+ }
326
+ }
327
+
328
+ static void
329
+ dumpFileDescriptorInfo(AbortHandlerWorkingState &state) {
330
+ char *messageBuf = state.messageBuf;
331
+ char *pos;
332
+ const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
333
+ struct stat buf;
334
+ int status;
335
+
336
+ pos = messageBuf;
337
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
338
+ pos = ASSU::appendData(pos, end, " ] Open files and file descriptors:\n");
339
+ write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);
340
+
341
+ status = runInSubprocessWithTimeLimit(state, dumpFileDescriptorInfoWithLsof, NULL, 4000);
342
+
343
+ if (status != 0) {
344
+ ASSU::printError("Falling back to another mechanism for dumping file descriptors.\n");
345
+
346
+ pos = messageBuf;
347
+ pos = ASSU::appendData(pos, end, "/proc/");
348
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
349
+ pos = ASSU::appendData(pos, end, "/fd");
350
+ *pos = '\0';
351
+ if (stat(messageBuf, &buf) == 0) {
352
+ dumpFileDescriptorInfoWithLs(state);
353
+ } else {
354
+ pos = messageBuf;
355
+ pos = ASSU::appendData(pos, end, "/dev/fd");
356
+ *pos = '\0';
357
+ if (stat(messageBuf, &buf) == 0) {
358
+ dumpFileDescriptorInfoWithLs(state);
359
+ } else {
360
+ pos = messageBuf;
361
+ pos = ASSU::appendData(pos, end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
362
+ write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);
363
+ }
364
+ }
365
+ }
366
+ }
367
+
368
+ static void
369
+ dumpWithCrashWatch(AbortHandlerWorkingState &state) {
370
+ char *pos;
371
+ const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
372
+
373
+ pos = state.messageBuf;
374
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
375
+ *pos = '\0';
376
+
377
+ pid_t child = asyncFork();
378
+ if (child == 0) {
379
+ closeAllFileDescriptors(2, true);
380
+ execlp(ctx->config->ruby, ctx->config->ruby, ctx->crashWatchCommand,
381
+ ctx->rubyLibDir, ctx->installSpec, "--dump",
382
+ state.messageBuf, // PID string
383
+ (char * const) 0);
384
+
385
+ const char *command[] = { "crash-watch", NULL };
386
+ printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
387
+ _exit(1);
388
+
389
+ } else if (child == -1) {
390
+ int e = errno;
391
+ pos = state.messageBuf;
392
+ pos = ASSU::appendData(pos, end, "Could not execute crash-watch: fork() failed: ");
393
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
394
+ pos = ASSU::appendData(pos, end, " (errno=");
395
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
396
+ pos = ASSU::appendData(pos, end, ")\n");
397
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
398
+
399
+ } else {
400
+ waitpid(child, NULL, 0);
401
+ }
402
+ }
403
+
404
+ #ifdef LIBC_HAS_BACKTRACE_FUNC
405
+ static void
406
+ dumpBacktrace(AbortHandlerWorkingState &state, void *userData) {
407
+ void *backtraceStore[512];
408
+ int frames = backtrace(backtraceStore, sizeof(backtraceStore) / sizeof(void *));
409
+ char *pos;
410
+ const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
411
+
412
+ pos = state.messageBuf;
413
+ pos = ASSU::appendData(pos, end, "--------------------------------------\n");
414
+ pos = ASSU::appendData(pos, end, "[ pid=");
415
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
416
+ pos = ASSU::appendData(pos, end, " ] Backtrace with ");
417
+ pos = ASSU::appendInteger<int, 10>(pos, end, frames);
418
+ pos = ASSU::appendData(pos, end, " frames:\n");
419
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
420
+
421
+ if (ctx->backtraceSanitizerCommand != NULL) {
422
+ int p[2];
423
+ if (pipe(p) == -1) {
424
+ int e = errno;
425
+ pos = state.messageBuf;
426
+ pos = ASSU::appendData(pos, end, "Could not dump diagnostics through backtrace sanitizer: pipe() failed with errno=");
427
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
428
+ pos = ASSU::appendData(pos, end, "\n");
429
+ pos = ASSU::appendData(pos, end, "Falling back to writing to stderr directly...\n");
430
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
431
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
432
+ return;
433
+ }
434
+
435
+ pid_t pid = asyncFork();
436
+ if (pid == 0) {
437
+ const char *pidStr = pos = state.messageBuf;
438
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
439
+ *pos = '\0';
440
+ pos++;
441
+
442
+ close(p[1]);
443
+ dup2(p[0], STDIN_FILENO);
444
+ closeAllFileDescriptors(2, true);
445
+
446
+ const char *command = pos;
447
+ pos = ASSU::appendData(pos, end, "exec ");
448
+ pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
449
+ if (ctx->backtraceSanitizerPassProgramInfo) {
450
+ pos = ASSU::appendData(pos, end, " \"");
451
+ pos = ASSU::appendData(pos, end, ctx->config->origArgv[0]);
452
+ pos = ASSU::appendData(pos, end, "\" ");
453
+ pos = ASSU::appendData(pos, end, pidStr);
454
+ }
455
+ *pos = '\0';
456
+ pos++;
457
+ execlp("/bin/sh", "/bin/sh", "-c", command, (const char * const) 0);
458
+
459
+ pos = state.messageBuf;
460
+ pos = ASSU::appendData(pos, end, "ERROR: cannot execute '");
461
+ pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
462
+ pos = ASSU::appendData(pos, end, "' for sanitizing the backtrace, trying 'cat'...\n");
463
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
464
+ execlp("cat", "cat", (const char * const) 0);
465
+ execlp("/bin/cat", "cat", (const char * const) 0);
466
+ execlp("/usr/bin/cat", "cat", (const char * const) 0);
467
+
468
+ const char *commandArray[] = { "cat", NULL };
469
+ printExecError2(commandArray, errno, state.messageBuf, sizeof(state.messageBuf));
470
+ _exit(1);
471
+
472
+ } else if (pid == -1) {
473
+ close(p[0]);
474
+ close(p[1]);
475
+ int e = errno;
476
+ pos = state.messageBuf;
477
+ pos = ASSU::appendData(pos, end, "Could not dump diagnostics through backtrace sanitizer: fork() failed: ");
478
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
479
+ pos = ASSU::appendData(pos, end, " (errno=");
480
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
481
+ pos = ASSU::appendData(pos, end, ")\n");
482
+ pos = ASSU::appendData(pos, end, "Falling back to writing to stderr directly...\n");
483
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
484
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
485
+
486
+ } else {
487
+ int status = -1;
488
+
489
+ close(p[0]);
490
+ backtrace_symbols_fd(backtraceStore, frames, p[1]);
491
+ close(p[1]);
492
+ if (waitpid(pid, &status, 0) == -1 || status != 0) {
493
+ pos = state.messageBuf;
494
+ pos = ASSU::appendData(pos, end, "ERROR: cannot execute '");
495
+ pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
496
+ pos = ASSU::appendData(pos, end, "' for sanitizing the backtrace, writing to stderr directly...\n");
497
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
498
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
499
+ }
500
+ }
501
+
502
+ } else {
503
+ backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
504
+ }
505
+ }
506
+ #endif
507
+
508
+ static void
509
+ runCustomDiagnosticsDumper(AbortHandlerWorkingState &state, void *userData) {
510
+ ctx->config->diagnosticsDumper(ctx->config->diagnosticsDumperUserData);
511
+ }
512
+
513
+ // This function is performed in a child process.
514
+ static void
515
+ dumpDiagnostics(AbortHandlerWorkingState &state) {
516
+ char *pos;
517
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
518
+ pid_t pid;
519
+ int status;
520
+
521
+ pos = state.messageBuf;
522
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
523
+ pos = ASSU::appendData(pos, end, " ] Date, uname and ulimits:\n");
524
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
525
+
526
+ // Dump human-readable time string and string.
527
+ pid = asyncFork();
528
+ if (pid == 0) {
529
+ closeAllFileDescriptors(2, true);
530
+ execlp("date", "date", (const char * const) 0);
531
+ _exit(1);
532
+ } else if (pid == -1) {
533
+ ASSU::printError("ERROR: Could not fork a process to dump the time!\n");
534
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
535
+ ASSU::printError("ERROR: Could not run 'date'!\n");
536
+ }
537
+
538
+ // Dump system uname.
539
+ pid = asyncFork();
540
+ if (pid == 0) {
541
+ closeAllFileDescriptors(2, true);
542
+ execlp("uname", "uname", "-mprsv", (const char * const) 0);
543
+ _exit(1);
544
+ } else if (pid == -1) {
545
+ ASSU::printError("ERROR: Could not fork a process to dump the uname!\n");
546
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
547
+ ASSU::printError("ERROR: Could not run 'uname -mprsv'!\n");
548
+ }
549
+
550
+ // Dump ulimit.
551
+ pid = asyncFork();
552
+ if (pid == 0) {
553
+ closeAllFileDescriptors(2, true);
554
+ execlp("ulimit", "ulimit", "-a", (const char * const) 0);
555
+ // On Linux 'ulimit' is a shell builtin, not a command.
556
+ execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (const char * const) 0);
557
+ _exit(1);
558
+ } else if (pid == -1) {
559
+ ASSU::printError("ERROR: Could not fork a process to dump the ulimit!\n");
560
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
561
+ ASSU::printError("ERROR: Could not run 'ulimit -a'!\n");
562
+ }
563
+
564
+ pos = state.messageBuf;
565
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
566
+ pos = ASSU::appendData(pos, end, " ] " PROGRAM_NAME " version: " PASSENGER_VERSION "\n");
567
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
568
+
569
+ if (LoggingKit::lastAssertionFailure.filename != NULL) {
570
+ pos = state.messageBuf;
571
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
572
+ pos = ASSU::appendData(pos, end, " ] Last assertion failure: (");
573
+ pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.expression);
574
+ pos = ASSU::appendData(pos, end, "), ");
575
+ if (LoggingKit::lastAssertionFailure.function != NULL) {
576
+ pos = ASSU::appendData(pos, end, "function ");
577
+ pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.function);
578
+ pos = ASSU::appendData(pos, end, ", ");
579
+ }
580
+ pos = ASSU::appendData(pos, end, "file ");
581
+ pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.filename);
582
+ pos = ASSU::appendData(pos, end, ", line ");
583
+ pos = ASSU::appendInteger<unsigned int, 10>(pos, end, LoggingKit::lastAssertionFailure.line);
584
+ pos = ASSU::appendData(pos, end, ".\n");
585
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
586
+ }
587
+
588
+ // It is important that writing the message and the backtrace are two
589
+ // seperate operations because it's not entirely clear whether the
590
+ // latter is async signal safe and thus can crash.
591
+ pos = state.messageBuf;
592
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
593
+ #ifdef LIBC_HAS_BACKTRACE_FUNC
594
+ pos = ASSU::appendData(pos, end, " ] libc backtrace available!\n");
595
+ #else
596
+ pos = ASSU::appendData(pos, end, " ] libc backtrace not available.\n");
597
+ #endif
598
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
599
+
600
+ #ifdef LIBC_HAS_BACKTRACE_FUNC
601
+ runInSubprocessWithTimeLimit(state, dumpBacktrace, NULL, 4000);
602
+ #endif
603
+
604
+ ASSU::printError("--------------------------------------\n");
605
+
606
+ if (ctx->config->diagnosticsDumper != NULL) {
607
+ pos = state.messageBuf;
608
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
609
+ pos = ASSU::appendData(pos, end, " ] Dumping additional diagnostical information...\n");
610
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
611
+ ASSU::printError("--------------------------------------\n");
612
+ runInSubprocessWithTimeLimit(state, runCustomDiagnosticsDumper, NULL, 2000);
613
+ ASSU::printError("--------------------------------------\n");
614
+ }
615
+
616
+ dumpFileDescriptorInfo(state);
617
+ ASSU::printError("--------------------------------------\n");
618
+
619
+ if (ctx->config->dumpWithCrashWatch && ctx->crashWatchCommand != NULL) {
620
+ pos = state.messageBuf;
621
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
622
+ #ifdef LIBC_HAS_BACKTRACE_FUNC
623
+ pos = ASSU::appendData(pos, end, " ] Dumping a more detailed backtrace with crash-watch...\n");
624
+ #else
625
+ pos = ASSU::appendData(pos, end, " ] Dumping a backtrace with crash-watch...\n");
626
+ #endif
627
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
628
+ dumpWithCrashWatch(state);
629
+ } else {
630
+ write_nowarn(STDERR_FILENO, "\n", 1);
631
+ }
632
+ }
633
+
634
+ static bool
635
+ createCrashLogFile(char *filename, size_t bufSize, time_t t) {
636
+ char *pos = filename;
637
+ const char *end = filename + bufSize - 1;
638
+ pos = ASSU::appendData(pos, end, "/var/tmp/passenger-crash-log.");
639
+ pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
640
+ *pos = '\0';
641
+
642
+ int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
643
+ if (fd == -1) {
644
+ pos = filename;
645
+ pos = ASSU::appendData(pos, end, "/tmp/passenger-crash-log.");
646
+ pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
647
+ *pos = '\0';
648
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
649
+ }
650
+ if (fd == -1) {
651
+ *filename = '\0';
652
+ return false;
653
+ } else {
654
+ close(fd);
655
+ return true;
656
+ }
657
+ }
658
+
659
+ static void
660
+ forkAndRedirectToTee(char *filename) {
661
+ pid_t pid;
662
+ int p[2];
663
+
664
+ if (pipe(p) == -1) {
665
+ // Signal error condition.
666
+ *filename = '\0';
667
+ return;
668
+ }
669
+
670
+ pid = asyncFork();
671
+ if (pid == 0) {
672
+ close(p[1]);
673
+ dup2(p[0], STDIN_FILENO);
674
+ execlp("tee", "tee", filename, (const char * const) 0);
675
+ execlp("/usr/bin/tee", "tee", filename, (const char * const) 0);
676
+ execlp("cat", "cat", (const char * const) 0);
677
+ execlp("/bin/cat", "cat", (const char * const) 0);
678
+ execlp("/usr/bin/cat", "cat", (const char * const) 0);
679
+ ASSU::printError("ERROR: cannot execute 'tee' or 'cat'; crash log will be lost!\n");
680
+ _exit(1);
681
+ } else if (pid == -1) {
682
+ ASSU::printError("ERROR: cannot fork a process for executing 'tee'\n");
683
+ *filename = '\0';
684
+ } else {
685
+ close(p[0]);
686
+ dup2(p[1], STDOUT_FILENO);
687
+ dup2(p[1], STDERR_FILENO);
688
+ }
689
+ }
690
+
691
+ static void
692
+ closeEmergencyPipes() {
693
+ if (ctx->emergencyPipe1[0] != -1) {
694
+ close(ctx->emergencyPipe1[0]);
695
+ }
696
+ if (ctx->emergencyPipe1[1] != -1) {
697
+ close(ctx->emergencyPipe1[1]);
698
+ }
699
+ if (ctx->emergencyPipe2[0] != -1) {
700
+ close(ctx->emergencyPipe2[0]);
701
+ }
702
+ if (ctx->emergencyPipe2[1] != -1) {
703
+ close(ctx->emergencyPipe2[1]);
704
+ }
705
+ ctx->emergencyPipe1[0] = ctx->emergencyPipe1[1] = -1;
706
+ ctx->emergencyPipe2[0] = ctx->emergencyPipe2[1] = -1;
707
+ }
708
+
709
+ static void
710
+ abortHandler(int signo, siginfo_t *info, void *_unused) {
711
+ AbortHandlerWorkingState state;
712
+
713
+ state.pid = getpid();
714
+ state.signo = signo;
715
+ state.info = info;
716
+ pid_t child;
717
+ time_t t = time(NULL);
718
+ char crashLogFile[256];
719
+
720
+ ctx->callCount++;
721
+ if (ctx->callCount > 1) {
722
+ // The abort handler itself crashed!
723
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
724
+ char *pos = state.messageBuf;
725
+ pos = ASSU::appendData(pos, end, "[ origpid=");
726
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
727
+ pos = ASSU::appendData(pos, end, ", pid=");
728
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, getpid());
729
+ pos = ASSU::appendData(pos, end, ", timestamp=");
730
+ pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
731
+ if (ctx->callCount == 2) {
732
+ // This is the first time it crashed.
733
+ pos = ASSU::appendData(pos, end, " ] Abort handler crashed! signo=");
734
+ pos = appendSignalName(pos, end, state.signo);
735
+ pos = ASSU::appendData(pos, end, ", reason=");
736
+ pos = appendSignalReason(pos, end, state.info);
737
+ pos = ASSU::appendData(pos, end, "\n");
738
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
739
+ // Run default signal handler.
740
+ raise(signo);
741
+ } else {
742
+ // This is the second time it crashed, meaning it failed to
743
+ // invoke the default signal handler to abort the process!
744
+ pos = ASSU::appendData(pos, end, " ] Abort handler crashed again! Force exiting this time. signo=");
745
+ pos = appendSignalName(pos, end, state.signo);
746
+ pos = ASSU::appendData(pos, end, ", reason=");
747
+ pos = appendSignalReason(pos, end, state.info);
748
+ pos = ASSU::appendData(pos, end, "\n");
749
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
750
+ _exit(1);
751
+ }
752
+ return;
753
+ }
754
+
755
+ closeEmergencyPipes();
756
+
757
+ /* We want to dump the entire crash log to both stderr and a log file.
758
+ * We use 'tee' for this.
759
+ */
760
+ if (createCrashLogFile(crashLogFile, sizeof(crashLogFile), t)) {
761
+ forkAndRedirectToTee(crashLogFile);
762
+ }
763
+
764
+ {
765
+ const char *end = state.messagePrefix + sizeof(state.messagePrefix);
766
+ char *pos = state.messagePrefix;
767
+ pos = ASSU::appendData(pos, end, "[ pid=");
768
+ pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
769
+ *pos = '\0';
770
+ }
771
+
772
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
773
+ char *pos = state.messageBuf;
774
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
775
+ pos = ASSU::appendData(pos, end, ", timestamp=");
776
+ pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
777
+ pos = ASSU::appendData(pos, end, " ] Process aborted! signo=");
778
+ pos = appendSignalName(pos, end, state.signo);
779
+ pos = ASSU::appendData(pos, end, ", reason=");
780
+ pos = appendSignalReason(pos, end, state.info);
781
+ pos = ASSU::appendData(pos, end, ", randomSeed=");
782
+ pos = ASSU::appendInteger<unsigned int, 10>(pos, end, ctx->config->randomSeed);
783
+ pos = ASSU::appendData(pos, end, "\n");
784
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
785
+
786
+ pos = state.messageBuf;
787
+ if (*crashLogFile != '\0') {
788
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
789
+ pos = ASSU::appendData(pos, end, " ] Crash log dumped to ");
790
+ pos = ASSU::appendData(pos, end, crashLogFile);
791
+ pos = ASSU::appendData(pos, end, "\n");
792
+ } else {
793
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
794
+ pos = ASSU::appendData(pos, end, " ] Could not create crash log file, so dumping to stderr only.\n");
795
+ }
796
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
797
+
798
+ if (ctx->config->beep) {
799
+ pos = state.messageBuf;
800
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
801
+ pos = ASSU::appendData(pos, end, " ] PASSENGER_BEEP_ON_ABORT on, executing beep...\n");
802
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
803
+
804
+ child = asyncFork();
805
+ if (child == 0) {
806
+ closeAllFileDescriptors(2, true);
807
+ #ifdef __APPLE__
808
+ const char *command[] = { "osascript", NULL };
809
+ execlp("osascript", "osascript", "-e", "beep 2", (const char * const) 0);
810
+ printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
811
+ #else
812
+ const char *command[] = { "beep", NULL };
813
+ execlp("beep", "beep", (const char * const) 0);
814
+ printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
815
+ #endif
816
+ _exit(1);
817
+
818
+ } else if (child == -1) {
819
+ int e = errno;
820
+ pos = state.messageBuf;
821
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
822
+ pos = ASSU::appendData(pos, end, " ] Could fork a child process for invoking a beep: fork() failed with errno=");
823
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
824
+ pos = ASSU::appendData(pos, end, "\n");
825
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
826
+ }
827
+ }
828
+
829
+ if (ctx->config->stopProcess) {
830
+ pos = state.messageBuf;
831
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
832
+ pos = ASSU::appendData(pos, end, " ] PASSENGER_STOP_ON_ABORT on, so process stopped. Send SIGCONT when you want to continue.\n");
833
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
834
+ raise(SIGSTOP);
835
+ }
836
+
837
+ // It isn't safe to call any waiting functions in this signal handler,
838
+ // not even read() and waitpid() even though they're async signal safe.
839
+ // So we fork a child process and let it dump as much diagnostics as possible
840
+ // instead of doing it in this process.
841
+ child = asyncFork();
842
+ if (child == 0) {
843
+ // Sleep for a short while to allow the parent process to raise SIGSTOP.
844
+ // usleep() and nanosleep() aren't async signal safe so we use select()
845
+ // instead.
846
+ struct timeval tv;
847
+ tv.tv_sec = 0;
848
+ tv.tv_usec = 100000;
849
+ select(0, NULL, NULL, NULL, &tv);
850
+
851
+ resetSignalHandlersAndMask();
852
+
853
+ child = asyncFork();
854
+ if (child == 0) {
855
+ // OS X: for some reason the SIGPIPE handler may be reset to default after forking.
856
+ // Later in this program we're going to pipe backtrace_symbols_fd() into the backtrace
857
+ // sanitizer, which may fail, and we don't want the diagnostics process to crash
858
+ // with SIGPIPE as a result, so we ignore SIGPIPE again.
859
+ ignoreSigpipe();
860
+ dumpDiagnostics(state);
861
+ // The child process may or may or may not resume the original process.
862
+ // We do it ourselves just to be sure.
863
+ kill(state.pid, SIGCONT);
864
+ _exit(0);
865
+
866
+ } else if (child == -1) {
867
+ int e = errno;
868
+ pos = state.messageBuf;
869
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
870
+ pos = ASSU::appendData(pos, end, "] Could fork a child process for dumping diagnostics: fork() failed with errno=");
871
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
872
+ pos = ASSU::appendData(pos, end, "\n");
873
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
874
+ _exit(1);
875
+
876
+ } else {
877
+ // Exit immediately so that child process is adopted by init process.
878
+ _exit(0);
879
+ }
880
+
881
+ } else if (child == -1) {
882
+ int e = errno;
883
+ pos = state.messageBuf;
884
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
885
+ pos = ASSU::appendData(pos, end, " ] Could fork a child process for dumping diagnostics: fork() failed with errno=");
886
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
887
+ pos = ASSU::appendData(pos, end, "\n");
888
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
889
+
890
+ } else {
891
+ raise(SIGSTOP);
892
+ // Will continue after the child process has done its job.
893
+ }
894
+
895
+ // Run default signal handler.
896
+ raise(signo);
897
+ }
898
+
899
+ void
900
+ installAbortHandler(const AbortHandlerConfig *config) {
901
+ ctx = new AbortHandlerContext();
902
+ memset(ctx, 0, sizeof(AbortHandlerContext));
903
+
904
+ ctx->config = config;
905
+ ctx->backtraceSanitizerPassProgramInfo = true;
906
+ ctx->emergencyPipe1[0] = -1;
907
+ ctx->emergencyPipe1[1] = -1;
908
+ ctx->emergencyPipe2[0] = -1;
909
+ ctx->emergencyPipe2[1] = -1;
910
+
911
+ abortHandlerConfigChanged();
912
+
913
+ IGNORE_SYSCALL_RESULT(pipe(ctx->emergencyPipe1));
914
+ IGNORE_SYSCALL_RESULT(pipe(ctx->emergencyPipe2));
915
+
916
+ size_t alternativeStackSize = MINSIGSTKSZ + 128 * 1024;
917
+ ctx->alternativeStack = (char *) malloc(alternativeStackSize);
918
+ if (ctx->alternativeStack == NULL) {
919
+ fprintf(stderr, "Cannot allocate an alternative stack with a size of %lu bytes!\n",
920
+ (unsigned long) alternativeStackSize);
921
+ fflush(stderr);
922
+ abort();
923
+ }
924
+
925
+ stack_t stack;
926
+ stack.ss_sp = ctx->alternativeStack;
927
+ stack.ss_size = alternativeStackSize;
928
+ stack.ss_flags = 0;
929
+ if (sigaltstack(&stack, NULL) != 0) {
930
+ int e = errno;
931
+ fprintf(stderr, "Cannot install an alternative stack for use in signal handlers: %s (%d)\n",
932
+ strerror(e), e);
933
+ fflush(stderr);
934
+ abort();
935
+ }
936
+
937
+ struct sigaction action;
938
+ action.sa_sigaction = abortHandler;
939
+ action.sa_flags = SA_RESETHAND | SA_SIGINFO;
940
+ sigemptyset(&action.sa_mask);
941
+ sigaction(SIGABRT, &action, NULL);
942
+ sigaction(SIGSEGV, &action, NULL);
943
+ sigaction(SIGBUS, &action, NULL);
944
+ sigaction(SIGFPE, &action, NULL);
945
+ sigaction(SIGILL, &action, NULL);
946
+ }
947
+
948
+ bool
949
+ abortHandlerInstalled() {
950
+ return ctx != NULL;
951
+ }
952
+
953
+ void
954
+ abortHandlerLogFds() {
955
+ if (ctx->emergencyPipe1[0] != -1) {
956
+ P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe1[0], __FILE__, __LINE__,
957
+ "Emergency pipe 1-0");
958
+ P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe1[1], __FILE__, __LINE__,
959
+ "Emergency pipe 1-1");
960
+ }
961
+ if (ctx->emergencyPipe2[0] != -1) {
962
+ P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe2[0], __FILE__, __LINE__,
963
+ "Emergency pipe 2-0");
964
+ P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe2[1], __FILE__, __LINE__,
965
+ "Emergency pipe 2-1");
966
+ }
967
+ }
968
+
969
+ static void
970
+ useCxxFiltAsBacktraceSanitizer() {
971
+ ctx->backtraceSanitizerCommand = strdup("c++filt -n");
972
+ ctx->backtraceSanitizerPassProgramInfo = false;
973
+ }
974
+
975
+ void
976
+ abortHandlerConfigChanged() {
977
+ const AbortHandlerConfig *config = ctx->config;
978
+ char *oldInstallSpec = ctx->installSpec;
979
+ char *oldRubyLibDir = ctx->rubyLibDir;
980
+ char *oldCrashWatchCommand = ctx->crashWatchCommand;
981
+ char *oldBacktraceSanitizerCommand = ctx->backtraceSanitizerCommand;
982
+
983
+ if (config->resourceLocator != NULL) {
984
+ string path;
985
+ const ResourceLocator *locator = config->resourceLocator;
986
+
987
+ ctx->installSpec = strdup(locator->getInstallSpec().c_str());
988
+ ctx->rubyLibDir = strdup(locator->getRubyLibDir().c_str());
989
+
990
+ path = locator->getHelperScriptsDir() + "/crash-watch.rb";
991
+ ctx->crashWatchCommand = strdup(path.c_str());
992
+
993
+ if (ctx->installSpec == NULL || ctx->rubyLibDir == NULL || ctx->crashWatchCommand == NULL) {
994
+ fprintf(stderr, "Cannot allocate memory for abort handler!\n");
995
+ fflush(stderr);
996
+ abort();
997
+ }
998
+
999
+ #ifdef __linux__
1000
+ path = StaticString(config->ruby) + " \""
1001
+ + locator->getHelperScriptsDir() +
1002
+ "/backtrace-sanitizer.rb\"";
1003
+ ctx->backtraceSanitizerCommand = strdup(path.c_str());
1004
+ ctx->backtraceSanitizerPassProgramInfo = true;
1005
+ if (ctx->backtraceSanitizerCommand == NULL) {
1006
+ fprintf(stderr, "Cannot allocate memory for abort handler!\n");
1007
+ fflush(stderr);
1008
+ abort();
1009
+ }
1010
+ #else
1011
+ useCxxFiltAsBacktraceSanitizer();
1012
+ #endif
1013
+ } else {
1014
+ ctx->installSpec = NULL;
1015
+ ctx->rubyLibDir = NULL;
1016
+ ctx->crashWatchCommand = NULL;
1017
+ useCxxFiltAsBacktraceSanitizer();
1018
+ }
1019
+
1020
+ free(oldInstallSpec);
1021
+ free(oldRubyLibDir);
1022
+ free(oldCrashWatchCommand);
1023
+ free(oldBacktraceSanitizerCommand);
1024
+ }
1025
+
1026
+ void
1027
+ shutdownAbortHandler() {
1028
+ free(ctx->installSpec);
1029
+ free(ctx->rubyLibDir);
1030
+ free(ctx->crashWatchCommand);
1031
+ free(ctx->backtraceSanitizerCommand);
1032
+ free(ctx->alternativeStack);
1033
+ closeEmergencyPipes();
1034
+ delete ctx;
1035
+ ctx = NULL;
1036
+ }
1037
+
1038
+
1039
+ } // namespace Fundamentals
1040
+ } // namespace Agent
1041
+ } // namespace Passenger
1042
+
1043
+
1044
+ /*
1045
+ * Override assert() to add more features and to fix bugs. We save the information
1046
+ * of the last assertion failure in a global variable so that we can print it
1047
+ * to the crash diagnostics report.
1048
+ */
1049
+ #if defined(__GLIBC__)
1050
+ extern "C" __attribute__ ((__noreturn__))
1051
+ void
1052
+ __assert_fail(__const char *__assertion, __const char *__file,
1053
+ unsigned int __line, __const char *__function)
1054
+ {
1055
+ using namespace Passenger;
1056
+
1057
+ LoggingKit::lastAssertionFailure.filename = __file;
1058
+ LoggingKit::lastAssertionFailure.line = __line;
1059
+ LoggingKit::lastAssertionFailure.function = __function;
1060
+ LoggingKit::lastAssertionFailure.expression = __assertion;
1061
+ fprintf(stderr, "Assertion failed! %s:%u: %s: %s\n", __file, __line, __function, __assertion);
1062
+ fflush(stderr);
1063
+ abort();
1064
+ }
1065
+
1066
+ #elif defined(__APPLE__)
1067
+ /* On OS X, raise() and abort() unfortunately send SIGABRT to the main thread,
1068
+ * causing the original backtrace to be lost in the signal handler.
1069
+ * We work around this for anything in the same linkage unit by just definin
1070
+ * our own versions of the assert handler and abort.
1071
+ */
1072
+
1073
+ #include <pthread.h>
1074
+
1075
+ extern "C" int
1076
+ raise(int sig) {
1077
+ return pthread_kill(pthread_self(), sig);
1078
+ }
1079
+
1080
+ extern "C" void
1081
+ __assert_rtn(const char *func, const char *file, int line, const char *expr) {
1082
+ using namespace Passenger;
1083
+
1084
+ LoggingKit::lastAssertionFailure.filename = file;
1085
+ LoggingKit::lastAssertionFailure.line = line;
1086
+ LoggingKit::lastAssertionFailure.function = func;
1087
+ LoggingKit::lastAssertionFailure.expression = expr;
1088
+ if (func) {
1089
+ fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n",
1090
+ expr, func, file, line);
1091
+ } else {
1092
+ fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n",
1093
+ expr, file, line);
1094
+ }
1095
+ fflush(stderr);
1096
+ abort();
1097
+ }
1098
+
1099
+ extern "C" void
1100
+ abort() {
1101
+ sigset_t set;
1102
+ sigemptyset(&set);
1103
+ sigaddset(&set, SIGABRT);
1104
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
1105
+ raise(SIGABRT);
1106
+ usleep(1000);
1107
+ __builtin_trap();
1108
+ }
1109
+ #endif /* __APPLE__ */