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.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/Rakefile +20 -17
- data/bin/passenger-install-apache2-module +14 -11
- data/build/agent.rb +45 -18
- data/build/apache2.rb +32 -16
- data/build/basics.rb +29 -40
- data/build/common_library.rb +70 -54
- data/build/cxx_tests.rb +34 -43
- data/build/integration_tests.rb +10 -10
- data/build/misc.rb +6 -6
- data/build/node_tests.rb +1 -2
- data/build/oxt_tests.rb +7 -5
- data/build/packaging.rb +11 -441
- data/build/ruby_extension.rb +1 -1
- data/build/ruby_tests.rb +1 -2
- data/build/support/cplusplus.rb +6 -5
- data/build/support/cxx_dependency_map.rb +357 -833
- data/build/support/general.rb +23 -1
- data/build/test_basics.rb +3 -28
- data/dev/ci/tests/rpm/Jenkinsfile +68 -0
- data/dev/ci/tests/rpm/run +63 -0
- data/dev/ci/tests/source-packaging/run +1 -1
- data/dev/ci/tests/source-packaging/setup +1 -1
- data/doc/{Packaging.txt.md → Packaging.md} +0 -0
- data/resources/templates/apache2/deployment_example.txt.erb +2 -2
- data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
- data/resources/templates/nginx/deployment_example.txt.erb +1 -1
- data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
- data/resources/templates/standalone/server.erb +2 -2
- data/src/agent/AgentMain.cpp +0 -4
- data/src/agent/Core/CoreMain.cpp +88 -5
- data/src/agent/Core/SpawningKit/Spawner.h +2 -1
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
- data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
- data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
- data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
- data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
- data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
- data/src/agent/Shared/Fundamentals/Utils.h +46 -0
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
- data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
- data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
- data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
- data/src/apache2_module/Hooks.cpp +4 -1
- data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
- data/src/cxx_supportlib/Constants.h +1 -2
- data/src/cxx_supportlib/Crypto.cpp +2 -1
- data/src/cxx_supportlib/Hooks.h +16 -37
- data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
- data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
- data/src/cxx_supportlib/Utils.cpp +41 -561
- data/src/cxx_supportlib/Utils.h +0 -68
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
- data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
- data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
- data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
- data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
- data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
- data/src/nginx_module/CacheLocationConfig.c +0 -75
- data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/Configuration.c +0 -1
- data/src/nginx_module/Configuration.h +0 -1
- data/src/nginx_module/ConfigurationCommands.c +1 -1
- data/src/nginx_module/ContentHandler.c +0 -1
- data/src/nginx_module/ContentHandler.h +0 -1
- data/src/nginx_module/CreateLocationConfig.c +0 -5
- data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/LocationConfig.h +0 -4
- data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
- data/src/nginx_module/MergeLocationConfig.c +0 -12
- data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/ngx_http_passenger_module.h +0 -1
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
- data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
- data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
- data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
- data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
- data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
- metadata +19 -97
- data/build/documentation.rb +0 -70
- data/doc/CloudLicensingConfiguration.html +0 -172
- data/doc/CloudLicensingConfiguration.txt.md +0 -3
- data/doc/Packaging.html +0 -488
- data/doc/Security of user switching support.idmap.txt +0 -34
- data/doc/Security of user switching support.txt +0 -197
- data/doc/ServerOptimizationGuide.html +0 -172
- data/doc/ServerOptimizationGuide.txt.md +0 -3
- data/doc/images/by_sa.png +0 -0
- data/doc/images/cloud_licensing_batch_job.png +0 -0
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +0 -251
- data/doc/images/glyphicons-halflings-white.png +0 -0
- data/doc/images/glyphicons-halflings.png +0 -0
- data/doc/images/icons/README +0 -5
- data/doc/images/icons/callouts/1.png +0 -0
- data/doc/images/icons/callouts/10.png +0 -0
- data/doc/images/icons/callouts/11.png +0 -0
- data/doc/images/icons/callouts/12.png +0 -0
- data/doc/images/icons/callouts/13.png +0 -0
- data/doc/images/icons/callouts/14.png +0 -0
- data/doc/images/icons/callouts/15.png +0 -0
- data/doc/images/icons/callouts/2.png +0 -0
- data/doc/images/icons/callouts/3.png +0 -0
- data/doc/images/icons/callouts/4.png +0 -0
- data/doc/images/icons/callouts/5.png +0 -0
- data/doc/images/icons/callouts/6.png +0 -0
- data/doc/images/icons/callouts/7.png +0 -0
- data/doc/images/icons/callouts/8.png +0 -0
- data/doc/images/icons/callouts/9.png +0 -0
- data/doc/images/icons/caution.png +0 -0
- data/doc/images/icons/example.png +0 -0
- data/doc/images/icons/home.png +0 -0
- data/doc/images/icons/important.png +0 -0
- data/doc/images/icons/next.png +0 -0
- data/doc/images/icons/note.png +0 -0
- data/doc/images/icons/prev.png +0 -0
- data/doc/images/icons/tip.png +0 -0
- data/doc/images/icons/up.png +0 -0
- data/doc/images/icons/warning.png +0 -0
- data/doc/images/many_web_framework_protocols.png +0 -0
- data/doc/images/passenger_architecture.png +0 -0
- data/doc/images/passenger_architecture.svg +0 -385
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/passenger_core_architecture.png +0 -0
- data/doc/images/passenger_nodejs_architecture.svg +0 -558
- data/doc/images/phusion_banner.png +0 -0
- data/doc/images/rack.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/smart_spawning.svg +0 -323
- data/doc/images/spawn_server_architecture.png +0 -0
- data/doc/images/spawn_server_architecture.svg +0 -655
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/images/typical_isolated_web_application.png +0 -0
- data/doc/images/typical_isolated_web_application.svg +0 -213
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
- data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
- data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
- data/doc/users_guide_snippets/deployment_basics.txt +0 -37
- data/doc/users_guide_snippets/enterprise_only.txt +0 -1
- data/doc/users_guide_snippets/environment_variables.txt +0 -44
- data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
- data/doc/users_guide_snippets/installation.txt +0 -228
- data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
- data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
- data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
- data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
- data/doc/users_guide_snippets/since_version.txt +0 -1
- data/doc/users_guide_snippets/support_information.txt +0 -8
- data/doc/users_guide_snippets/tips.txt +0 -302
- data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
- data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
- data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
- data/src/agent/Shared/Base.cpp +0 -1678
- data/src/agent/UstRouter/ApiServer.h +0 -292
- data/src/agent/UstRouter/Client.h +0 -112
- data/src/agent/UstRouter/Controller.h +0 -1309
- data/src/agent/UstRouter/LogSink.h +0 -145
- data/src/agent/UstRouter/OptionParser.h +0 -180
- data/src/agent/UstRouter/RemoteSender.h +0 -853
- data/src/agent/UstRouter/RemoteSink.h +0 -145
- data/src/agent/UstRouter/Transaction.h +0 -278
- data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
- data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
- 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__ */
|