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