!C99Shell v. 2.0 [PHP 7 Update] [25.02.2019]!

Software: Apache. PHP/5.6.40 

uname -a: Linux cpanel06wh.bkk1.cloud.z.com 2.6.32-954.3.5.lve1.4.80.el6.x86_64 #1 SMP Thu Sep 24
01:42:00 EDT 2020 x86_64
 

uid=851(cp949260) gid=853(cp949260) groups=853(cp949260) 

Safe-mode: OFF (not secure)

/opt/passenger-5.3.7-4.el6.cloudlinux/src/agent/Shared/Fundamentals/   drwxr-xr-x
Free 203.96 GB of 981.82 GB (20.77%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     AbortHandler.cpp (42.33 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  Phusion Passenger - https://www.phusionpassenger.com/
 *  Copyright (c) 2010-2017 Phusion Holding B.V.
 *
 *  "Passenger", "Phusion Passenger" and "Union Station" are registered
 *  trademarks of Phusion Holding B.V.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */

#include <Shared/Fundamentals/AbortHandler.h>

#include <boost/cstdint.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <cstdio>
#include <cstdlib>
#include <cstddef>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <signal.h>
#include <libgen.h>

#ifdef __linux__
    #include <sys/syscall.h>
    #include <features.h>
#endif
#if defined(__APPLE__) || defined(__GNU_LIBRARY__)
    #define LIBC_HAS_BACKTRACE_FUNC
#endif
#ifdef LIBC_HAS_BACKTRACE_FUNC
    #include <execinfo.h>
#endif

#include <Shared/Fundamentals/AbortHandler.h>
#include <Shared/Fundamentals/Utils.h>
#include <Constants.h>
#include <LoggingKit/LoggingKit.h>
#include <LoggingKit/Context.h>
#include <ResourceLocator.h>
#include <RandomGenerator.h>
#include <ProcessManagement/Utils.h>
#include <Utils.h>
#include <Utils/AsyncSignalSafeUtils.h>

namespace Passenger {
namespace Agent {
namespace Fundamentals {

using namespace std;
namespace ASSU = AsyncSignalSafeUtils;

#define RANDOM_TOKEN_SIZE 6
#define MAX_RANDOM_TOKENS 256


struct AbortHandlerContext {
    const AbortHandlerConfig *config;
    char *installSpec;
    char *rubyLibDir;
    char *tmpDir;
    char *crashWatchCommand;
    char *backtraceSanitizerCommand;
    bool backtraceSanitizerPassProgramInfo;

    /**
     * A string of RANDOM_TOKEN_SIZE * MAX_RANDOM_SIZES bytes.
     * Used by createCrashLogDir() to find a unique directory name.
     */
    char *randomTokens;

    int emergencyPipe1[2];
    int emergencyPipe2[2];

    char *alternativeStack;

    volatile sig_atomic_t callCount;
};

struct AbortHandlerWorkingState {
    pid_t pid;
    int signo;
    siginfo_t *info;

    char messagePrefix[32];
    char messageBuf[1024];

    char crashLogDir[256];
    int crashLogDirFd;
};

typedef void (*Callback)(AbortHandlerWorkingState &state, void *userData);


#define IGNORE_SYSCALL_RESULT(code) \
    do { \
        int _ret = code; \
        (void) _ret; \
    } while (false)


static AbortHandlerContext *ctx = NULL;
static const char digits[] = "0123456789";
static const char hex_chars[] = "0123456789abcdef";


static void
write_nowarn(int fd, const void *buf, size_t n) {
    ASSU::writeNoWarn(fd, buf, n);
}

static void
printCrashLogFileCreated(AbortHandlerWorkingState &state, const char *fname) {
    const char *end = state.messageBuf + sizeof(state.messageBuf);
    char *pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, "Dumping to ");
    pos = ASSU::appendData(pos, end, state.crashLogDir);
    pos = ASSU::appendData(pos, end, "/");
    pos = ASSU::appendData(pos, end, fname);
    pos = ASSU::appendData(pos, end, "\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
}

static void
printCrashLogFileCreationError(AbortHandlerWorkingState &state, const char *fname, int e) {
    const char *end = state.messageBuf + sizeof(state.messageBuf);
    char *pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, "Error creating ");
    pos = ASSU::appendData(pos, end, state.crashLogDir);
    pos = ASSU::appendData(pos, end, "/");
    pos = ASSU::appendData(pos, end, fname);
    pos = ASSU::appendData(pos, end, ": ");
    pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
    pos = ASSU::appendData(pos, end, " (errno=");
    pos = ASSU::appendInteger<int, 10>(pos, end, e);
    pos = ASSU::appendData(pos, end, ")\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
}

static char *
appendSignalName(char *pos, const char *end, int signo) {
    switch (signo) {
    case SIGABRT:
        pos = ASSU::appendData(pos, end, "SIGABRT");
        break;
    case SIGSEGV:
        pos = ASSU::appendData(pos, end, "SIGSEGV");
        break;
    case SIGBUS:
        pos = ASSU::appendData(pos, end, "SIGBUS");
        break;
    case SIGFPE:
        pos = ASSU::appendData(pos, end, "SIGFPE");
        break;
    case SIGILL:
        pos = ASSU::appendData(pos, end, "SIGILL");
        break;
    default:
        return ASSU::appendInteger<int, 10>(pos, end, signo);
    }
    pos = ASSU::appendData(pos, end, "(");
    pos = ASSU::appendInteger<int, 10>(pos, end, signo);
    pos = ASSU::appendData(pos, end, ")");
    return pos;
}

#define SI_CODE_HANDLER(name) \
    case name: \
        buf = ASSU::appendData(buf, end, #name); \
        break

// Must be async signal safe.
static char *
appendSignalReason(char *buf, const char *end, siginfo_t *info) {
    bool handled = true;

    switch (info->si_code) {
    SI_CODE_HANDLER(SI_USER);
    #ifdef SI_KERNEL
        SI_CODE_HANDLER(SI_KERNEL);
    #endif
    SI_CODE_HANDLER(SI_QUEUE);
    SI_CODE_HANDLER(SI_TIMER);
    #ifdef SI_ASYNCIO
        SI_CODE_HANDLER(SI_ASYNCIO);
    #endif
    #ifdef SI_MESGQ
        SI_CODE_HANDLER(SI_MESGQ);
    #endif
    #ifdef SI_SIGIO
        SI_CODE_HANDLER(SI_SIGIO);
    #endif
    #ifdef SI_TKILL
        SI_CODE_HANDLER(SI_TKILL);
    #endif
    default:
        switch (info->si_signo) {
        case SIGSEGV:
            switch (info->si_code) {
            #ifdef SEGV_MAPERR
                SI_CODE_HANDLER(SEGV_MAPERR);
            #endif
            #ifdef SEGV_ACCERR
                SI_CODE_HANDLER(SEGV_ACCERR);
            #endif
            default:
                handled = false;
                break;
            }
            break;
        case SIGBUS:
            switch (info->si_code) {
            #ifdef BUS_ADRALN
                SI_CODE_HANDLER(BUS_ADRALN);
            #endif
            #ifdef BUS_ADRERR
                SI_CODE_HANDLER(BUS_ADRERR);
            #endif
            #ifdef BUS_OBJERR
                SI_CODE_HANDLER(BUS_OBJERR);
            #endif
            default:
                handled = false;
                break;
            }
            break;
        default:
            handled = false;
            break;
        }
        if (!handled) {
            buf = ASSU::appendData(buf, end, "#");
            buf = ASSU::appendInteger<int, 10>(buf, end, info->si_code);
        }
        break;
    }

    if (info->si_code <= 0) {
        buf = ASSU::appendData(buf, end, ", signal sent by PID ");
        buf = ASSU::appendInteger<pid_t, 10>(buf, end, info->si_pid);
        buf = ASSU::appendData(buf, end, " with UID ");
        buf = ASSU::appendInteger<uid_t, 10>(buf, end, info->si_uid);
    }

    buf = ASSU::appendData(buf, end, ", si_addr=0x");
    buf = ASSU::appendInteger<boost::uintptr_t, 16>(buf, end, (boost::uintptr_t) info->si_addr);

    return buf;
}

static int
runInSubprocessWithTimeLimit(AbortHandlerWorkingState &state, Callback callback, void *userData, int timeLimit) {
    char *pos;
    const char *end = state.messageBuf + sizeof(state.messageBuf);
    pid_t child;
    int p[2], e;

    if (pipe(p) == -1) {
        e = errno;
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "Could not create subprocess: pipe() failed: ");
        pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
        pos = ASSU::appendData(pos, end, " (errno=");
        pos = ASSU::appendInteger<int, 10>(pos, end, e);
        pos = ASSU::appendData(pos, end, ")\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        return -1;
    }

    child = asyncFork();
    if (child == 0) {
        close(p[0]);
        callback(state, userData);
        _exit(0);
        return -1;

    } else if (child == -1) {
        e = errno;
        close(p[0]);
        close(p[1]);
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "Could not create subprocess: fork() failed: ");
        pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
        pos = ASSU::appendData(pos, end, " (errno=");
        pos = ASSU::appendInteger<int, 10>(pos, end, e);
        pos = ASSU::appendData(pos, end, ")\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        return -1;

    } else {
        int status;
        close(p[1]);

        // We give the child process a time limit. If it doesn't succeed in
        // exiting within the time limit, we assume that it has frozen
        // and we kill it.
        struct pollfd fd;
        fd.fd = p[0];
        fd.events = POLLIN | POLLHUP | POLLERR;
        if (poll(&fd, 1, timeLimit) <= 0) {
            kill(child, SIGKILL);
            ASSU::printError("Could not run child process: it did not exit in time\n");
        }
        close(p[0]);
        if (waitpid(child, &status, 0) == child) {
            return status;
        } else {
            return -1;
        }
    }
}

static void
dumpUlimits(AbortHandlerWorkingState &state) {
    const char *end = state.messageBuf + sizeof(state.messageBuf);
    char *pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    pos = ASSU::appendData(pos, end, " ] Dumping ulimits...\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    int fd = -1;
    if (state.crashLogDirFd != -1) {
        fd = openat(state.crashLogDirFd, "ulimits.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd != -1) {
            printCrashLogFileCreated(state, "ulimits.log");
        } else {
            printCrashLogFileCreationError(state, "ulimits.log", errno);
        }
    }

    pid_t pid = asyncFork();
    int status;
    if (pid == 0) {
        if (fd != -1) {
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
        }
        closeAllFileDescriptors(2, true);
        execlp("ulimit", "ulimit", "-a", (char *) 0);
        // On Linux 'ulimit' is a shell builtin, not a command.
        execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (char *) 0);
        _exit(1);
    } else if (pid == -1) {
        ASSU::printError("ERROR: Could not fork a process to dump the ulimit!\n");
    } else if (waitpid(pid, &status, 0) != pid || status != 0) {
        ASSU::printError("ERROR: Could not run 'ulimit -a'!\n");
    }

    if (fd != -1) {
        close(fd);
    }
}

static void
dumpFileDescriptorInfoWithLsof(AbortHandlerWorkingState &state, void *userData) {
    if (state.crashLogDirFd != -1) {
        int fd = openat(state.crashLogDirFd, "fds.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd != -1) {
            printCrashLogFileCreated(state, "fds.log");
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
            close(fd);
        } else {
            printCrashLogFileCreationError(state, "fds.log", errno);
        }
    }

    char *pos = state.messageBuf;
    const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
    pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
    *pos = '\0';

    closeAllFileDescriptors(2, true);

    execlp("lsof", "lsof", "-p", state.messageBuf, "-nP", (char *) 0);

    const char *command[] = { "lsof", NULL };
    printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
    _exit(1);
}

static void
dumpFileDescriptorInfoWithLs(AbortHandlerWorkingState &state, const char *path) {
    pid_t pid;
    int fd = -1;
    int status;

    if (state.crashLogDirFd != -1) {
        fd = openat(state.crashLogDirFd, "fds.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd != -1) {
            printCrashLogFileCreated(state, "fds.log");
        } else {
            printCrashLogFileCreationError(state, "fds.log", errno);
        }
    }

    pid = asyncFork();
    if (pid == 0) {
        if (fd != -1) {
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
        }

        const char *end = state.messageBuf + sizeof(state.messageBuf);
        char *pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "Running: ls -lv ");
        pos = ASSU::appendData(pos, end, path);
        pos = ASSU::appendData(pos, end, "\n");
        pos = ASSU::appendData(pos, end, "--------------------------\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

        closeAllFileDescriptors(2, true);
        // The '-v' is for natural sorting on Linux. On BSD -v means something else but it's harmless.
        execlp("ls", "ls", "-lv", path, (char *) 0);

        const char *command[] = { "ls", NULL };
        printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
        _exit(1);
    } else if (pid == -1) {
        ASSU::printError("ERROR: Could not fork a process to dump file descriptor information!\n");
    } else if (waitpid(pid, &status, 0) != pid || status != 0) {
        ASSU::printError("ERROR: Could not run 'ls' to dump file descriptor information!\n");
    }

    if (fd != -1) {
        close(fd);
    }
}

static void
dumpFileDescriptorInfo(AbortHandlerWorkingState &state) {
    char *messageBuf = state.messageBuf;
    char *pos;
    const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
    struct stat buf;
    int status;

    pos = messageBuf;
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    pos = ASSU::appendData(pos, end, " ] Open files and file descriptors:\n");
    write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);

    status = runInSubprocessWithTimeLimit(state, dumpFileDescriptorInfoWithLsof, NULL, 4000);

    if (status != 0) {
        char path[256];
        ASSU::printError("Falling back to another mechanism for dumping file descriptors.\n");

        pos = path;
        end = path + sizeof(path) - 1;
        pos = ASSU::appendData(pos, end, "/proc/");
        pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
        pos = ASSU::appendData(pos, end, "/fd");
        *pos = '\0';
        if (stat(path, &buf) == 0) {
            dumpFileDescriptorInfoWithLs(state, path);
            return;
        }

        pos = path;
        pos = ASSU::appendData(pos, end, "/dev/fd");
        *pos = '\0';
        if (stat(path, &buf) == 0) {
            dumpFileDescriptorInfoWithLs(state, path);
            return;
        }

        pos = messageBuf;
        pos = ASSU::appendData(pos, end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
        write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);
    }
}

static void
dumpWithCrashWatch(AbortHandlerWorkingState &state) {
    int fd = -1;

    if (state.crashLogDirFd != -1) {
        fd = openat(state.crashLogDirFd, "backtrace.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd != -1) {
            printCrashLogFileCreated(state, "backtrace.log");
        } else {
            printCrashLogFileCreationError(state, "backtrace.log", errno);
        }
    }

    char *pos = state.messageBuf;
    const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
    pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
    *pos = '\0';

    pid_t child = asyncFork();
    if (child == 0) {
        if (fd != -1) {
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
        }
        closeAllFileDescriptors(2, true);
        execlp(ctx->config->ruby, ctx->config->ruby, ctx->crashWatchCommand,
            ctx->rubyLibDir, ctx->installSpec, "--dump",
            state.messageBuf, // PID string
            (char *) 0);

        const char *command[] = { "crash-watch", NULL };
        printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
        _exit(1);

    } else if (child == -1) {
        int e = errno;
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "Could not execute crash-watch: fork() failed: ");
        pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
        pos = ASSU::appendData(pos, end, " (errno=");
        pos = ASSU::appendInteger<int, 10>(pos, end, e);
        pos = ASSU::appendData(pos, end, ")\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    } else {
        waitpid(child, NULL, 0);
    }

    if (fd != -1) {
        close(fd);
    }
}

#ifdef LIBC_HAS_BACKTRACE_FUNC
    static void
    dumpBacktrace(AbortHandlerWorkingState &state, void *userData) {
        void *backtraceStore[512];
        int frames = backtrace(backtraceStore, sizeof(backtraceStore) / sizeof(void *));
        char *pos;
        const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;

        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "--------------------------------------\n");
        pos = ASSU::appendData(pos, end, "[ pid=");
        pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
        pos = ASSU::appendData(pos, end, " ] Backtrace with ");
        pos = ASSU::appendInteger<int, 10>(pos, end, frames);
        pos = ASSU::appendData(pos, end, " frames:\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

        if (ctx->backtraceSanitizerCommand != NULL) {
            int p[2];
            if (pipe(p) == -1) {
                int e = errno;
                pos = state.messageBuf;
                pos = ASSU::appendData(pos, end, "Could not dump diagnostics through backtrace sanitizer: pipe() failed with errno=");
                pos = ASSU::appendInteger<int, 10>(pos, end, e);
                pos = ASSU::appendData(pos, end, "\n");
                pos = ASSU::appendData(pos, end, "Falling back to writing to stderr directly...\n");
                write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
                backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
                return;
            }

            pid_t pid = asyncFork();
            if (pid == 0) {
                const char *pidStr = pos = state.messageBuf;
                pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
                *pos = '\0';
                pos++;

                close(p[1]);
                dup2(p[0], STDIN_FILENO);
                closeAllFileDescriptors(2, true);

                const char *command = pos;
                pos = ASSU::appendData(pos, end, "exec ");
                pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
                if (ctx->backtraceSanitizerPassProgramInfo) {
                    pos = ASSU::appendData(pos, end, " \"");
                    pos = ASSU::appendData(pos, end, ctx->config->origArgv[0]);
                    pos = ASSU::appendData(pos, end, "\" ");
                    pos = ASSU::appendData(pos, end, pidStr);
                }
                *pos = '\0';
                pos++;
                execlp("/bin/sh", "/bin/sh", "-c", command, (char *) 0);

                pos = state.messageBuf;
                pos = ASSU::appendData(pos, end, "ERROR: cannot execute '");
                pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
                pos = ASSU::appendData(pos, end, "' for sanitizing the backtrace, trying 'cat'...\n");
                write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
                execlp("cat", "cat", (char *) 0);
                execlp("/bin/cat", "cat", (char *) 0);
                execlp("/usr/bin/cat", "cat", (char *) 0);

                const char *commandArray[] = { "cat", NULL };
                printExecError2(commandArray, errno, state.messageBuf, sizeof(state.messageBuf));
                _exit(1);

            } else if (pid == -1) {
                close(p[0]);
                close(p[1]);
                int e = errno;
                pos = state.messageBuf;
                pos = ASSU::appendData(pos, end, "Could not dump diagnostics through backtrace sanitizer: fork() failed: ");
                pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
                pos = ASSU::appendData(pos, end, " (errno=");
                pos = ASSU::appendInteger<int, 10>(pos, end, e);
                pos = ASSU::appendData(pos, end, ")\n");
                pos = ASSU::appendData(pos, end, "Falling back to writing to stderr directly...\n");
                write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
                backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);

            } else {
                int status = -1;

                close(p[0]);
                backtrace_symbols_fd(backtraceStore, frames, p[1]);
                close(p[1]);
                if (waitpid(pid, &status, 0) == -1 || status != 0) {
                    pos = state.messageBuf;
                    pos = ASSU::appendData(pos, end, "ERROR: cannot execute '");
                    pos = ASSU::appendData(pos, end, ctx->backtraceSanitizerCommand);
                    pos = ASSU::appendData(pos, end, "' for sanitizing the backtrace, writing to stderr directly...\n");
                    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
                    backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
                }
            }

        } else {
            backtrace_symbols_fd(backtraceStore, frames, STDERR_FILENO);
        }
    }
#endif

static void
runCustomDiagnosticsDumper(AbortHandlerWorkingState &state, void *userData) {
    unsigned int i = static_cast<unsigned int>(reinterpret_cast<boost::uintptr_t>(userData));
    const AbortHandlerConfig::DiagnosticsDumper &dumper = ctx->config->diagnosticsDumpers[i];

    if (state.crashLogDirFd != -1) {
        int fd = openat(state.crashLogDirFd, dumper.logFileName, O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd != -1) {
            printCrashLogFileCreated(state, dumper.logFileName);
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
            close(fd);
        } else {
            printCrashLogFileCreationError(state, dumper.logFileName, errno);
        }
    }

    dumper.func(dumper.userData);
}

// This function is performed in a child process.
static void
dumpDiagnostics(AbortHandlerWorkingState &state) {
    char *pos;
    const char *end = state.messageBuf + sizeof(state.messageBuf);
    pid_t pid;
    int status;

    pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    pos = ASSU::appendData(pos, end, " ] Date and uname:\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    // Dump human-readable time string and string.
    pid = asyncFork();
    if (pid == 0) {
        closeAllFileDescriptors(2, true);
        execlp("date", "date", (char *) 0);
        _exit(1);
    } else if (pid == -1) {
        ASSU::printError("ERROR: Could not fork a process to dump the time!\n");
    } else if (waitpid(pid, &status, 0) != pid || status != 0) {
        ASSU::printError("ERROR: Could not run 'date'!\n");
    }

    // Dump system uname.
    pid = asyncFork();
    if (pid == 0) {
        closeAllFileDescriptors(2, true);
        execlp("uname", "uname", "-mprsv", (char *) 0);
        _exit(1);
    } else if (pid == -1) {
        ASSU::printError("ERROR: Could not fork a process to dump the uname!\n");
    } else if (waitpid(pid, &status, 0) != pid || status != 0) {
        ASSU::printError("ERROR: Could not run 'uname -mprsv'!\n");
    }

    pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    pos = ASSU::appendData(pos, end, " ] " PROGRAM_NAME " version: " PASSENGER_VERSION "\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    if (LoggingKit::lastAssertionFailure.filename != NULL) {
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Last assertion failure: (");
        pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.expression);
        pos = ASSU::appendData(pos, end, "), ");
        if (LoggingKit::lastAssertionFailure.function != NULL) {
            pos = ASSU::appendData(pos, end, "function ");
            pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.function);
            pos = ASSU::appendData(pos, end, ", ");
        }
        pos = ASSU::appendData(pos, end, "file ");
        pos = ASSU::appendData(pos, end, LoggingKit::lastAssertionFailure.filename);
        pos = ASSU::appendData(pos, end, ", line ");
        pos = ASSU::appendInteger<unsigned int, 10>(pos, end, LoggingKit::lastAssertionFailure.line);
        pos = ASSU::appendData(pos, end, ".\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
    }

    // It is important that writing the message and the backtrace are two
    // seperate operations because it's not entirely clear whether the
    // latter is async signal safe and thus can crash.
    pos = state.messageBuf;
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    #ifdef LIBC_HAS_BACKTRACE_FUNC
        pos = ASSU::appendData(pos, end, " ] libc backtrace available!\n");
    #else
        pos = ASSU::appendData(pos, end, " ] libc backtrace not available.\n");
    #endif
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    #ifdef LIBC_HAS_BACKTRACE_FUNC
        runInSubprocessWithTimeLimit(state, dumpBacktrace, NULL, 4000);
    #endif

    ASSU::printError("--------------------------------------\n");

    dumpUlimits(state);

    ASSU::printError("--------------------------------------\n");

    for (unsigned int i = 0; i < AbortHandlerConfig::MAX_DIAGNOSTICS_DUMPERS; i++) {
        const AbortHandlerConfig::DiagnosticsDumper &diagnosticsDumper = ctx->config->diagnosticsDumpers[i];
        if (diagnosticsDumper.func == NULL) {
            continue;
        }

        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Dumping ");
        pos = ASSU::appendData(pos, end, diagnosticsDumper.name);
        pos = ASSU::appendData(pos, end, "...\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        runInSubprocessWithTimeLimit(state, runCustomDiagnosticsDumper,
            reinterpret_cast<void *>(static_cast<boost::uintptr_t>(i)), 2000);
        ASSU::printError("--------------------------------------\n");
    }

    dumpFileDescriptorInfo(state);
    ASSU::printError("--------------------------------------\n");

    if (ctx->config->dumpWithCrashWatch && ctx->crashWatchCommand != NULL) {
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        #ifdef LIBC_HAS_BACKTRACE_FUNC
            pos = ASSU::appendData(pos, end, " ] Dumping a more detailed backtrace with crash-watch...\n");
        #else
            pos = ASSU::appendData(pos, end, " ] Dumping a backtrace with crash-watch...\n");
        #endif
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        dumpWithCrashWatch(state);
    } else {
        write_nowarn(STDERR_FILENO, "\n", 1);
    }

    if (state.crashLogDir[0] != '\0') {
        ASSU::printError("--------------------------------------\n");
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] **************** LOOK HERE FOR CRASH DETAILS *****************\n\n");
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Crash log dumped to this directory:\n");
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] ");
        pos = ASSU::appendData(pos, end, state.crashLogDir);
        pos = ASSU::appendData(pos, end, "\n\n");
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] **************** LOOK ABOVE FOR CRASH DETAILS ****************\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
    }
}

static bool
createCrashLogDir(AbortHandlerWorkingState &state, time_t t) {
    char *suffixBegin = state.crashLogDir;
    const char *end = state.crashLogDir + sizeof(state.crashLogDir) - 1;
    suffixBegin = ASSU::appendData(suffixBegin, end, "/var/tmp/passenger-crash-log.");
    suffixBegin = ASSU::appendInteger<time_t, 10>(suffixBegin, end, t);
    suffixBegin = ASSU::appendData(suffixBegin, end, ".");

    // Try a bunch of times to find and create a unique path.
    for (unsigned int i = 0; i < MAX_RANDOM_TOKENS; i++) {
        char *pos = suffixBegin;
        pos = ASSU::appendData(pos, end, ctx->randomTokens + RANDOM_TOKEN_SIZE * i,
            RANDOM_TOKEN_SIZE);
        *pos = '\0';

        int ret;
        do {
            ret = mkdir(state.crashLogDir, 0700);
        } while (ret == -1 && errno == EINTR);
        if (ret == -1) {
            if (errno == EEXIST) {
                // Directory exists; try again.
                continue;
            } else {
                int e = errno;
                end = state.messageBuf + sizeof(state.messageBuf);
                pos = state.messageBuf;
                pos = ASSU::appendData(pos, end, state.messagePrefix);
                pos = ASSU::appendData(pos, end, " ] Error creating directory ");
                pos = ASSU::appendData(pos, end, state.crashLogDir);
                pos = ASSU::appendData(pos, end, " for storing crash log: ");
                pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
                pos = ASSU::appendData(pos, end, " (errno=");
                pos = ASSU::appendInteger<int, 10>(pos, end, e);
                pos = ASSU::appendData(pos, end, ")\n");
                write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
                state.crashLogDir[0] = '\0';
                return false;
            }
        }

        do {
            state.crashLogDirFd = open(state.crashLogDir, O_RDONLY);
        } while (state.crashLogDirFd == -1 && errno == EINTR);
        if (state.crashLogDirFd == -1) {
            int e = errno;
            end = state.messageBuf + sizeof(state.messageBuf);
            pos = state.messageBuf;
            pos = ASSU::appendData(pos, end, state.messagePrefix);
            pos = ASSU::appendData(pos, end, " ] Error opening created directory ");
            pos = ASSU::appendData(pos, end, state.crashLogDir);
            pos = ASSU::appendData(pos, end, " for storing crash log: ");
            pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
            pos = ASSU::appendData(pos, end, " (errno=");
            pos = ASSU::appendInteger<int, 10>(pos, end, e);
            pos = ASSU::appendData(pos, end, ")\n");
            write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
            state.crashLogDir[0] = '\0';
            return false;
        }

        return true;
    }

    state.crashLogDir[0] = '\0';
    return false;
}

static bool
forkAndRedirectToTeeAndMainLogFile(const char *crashLogDir) {
    int p[2];
    if (pipe(p) == -1) {
        return false;
    }

    char filename[300];
    char *pos = filename;
    const char *end = filename + sizeof(filename) - 1;

    pos = ASSU::appendData(pos, end, crashLogDir);
    pos = ASSU::appendData(pos, end, "/");
    pos = ASSU::appendData(pos, end, "main.log");
    *pos = '\0';

    pid_t pid = asyncFork();
    if (pid == 0) {
        close(p[1]);
        dup2(p[0], STDIN_FILENO);
        execlp("tee", "tee", filename, (char *) 0);
        execlp("/usr/bin/tee", "tee", filename, (char *) 0);
        execlp("cat", "cat", (char *) 0);
        execlp("/bin/cat", "cat", (char *) 0);
        execlp("/usr/bin/cat", "cat", (char *) 0);
        ASSU::printError("ERROR: cannot execute 'tee' or 'cat'; crash log will be lost!\n");
        _exit(1);
        return false;
    } else if (pid == -1) {
        ASSU::printError("ERROR: cannot fork a process for executing 'tee'\n");
        return false;
    } else {
        close(p[0]);
        dup2(p[1], STDOUT_FILENO);
        dup2(p[1], STDERR_FILENO);
        return true;
    }
}

static void
closeEmergencyPipes() {
    if (ctx->emergencyPipe1[0] != -1) {
        close(ctx->emergencyPipe1[0]);
    }
    if (ctx->emergencyPipe1[1] != -1) {
        close(ctx->emergencyPipe1[1]);
    }
    if (ctx->emergencyPipe2[0] != -1) {
        close(ctx->emergencyPipe2[0]);
    }
    if (ctx->emergencyPipe2[1] != -1) {
        close(ctx->emergencyPipe2[1]);
    }
    ctx->emergencyPipe1[0] = ctx->emergencyPipe1[1] = -1;
    ctx->emergencyPipe2[0] = ctx->emergencyPipe2[1] = -1;
}

static void
abortHandler(int signo, siginfo_t *info, void *_unused) {
    AbortHandlerWorkingState state;

    state.pid = getpid();
    state.signo = signo;
    state.info = info;
    pid_t child;
    time_t t = time(NULL);

    ctx->callCount++;
    if (ctx->callCount > 1) {
        // The abort handler itself crashed!
        const char *end = state.messageBuf + sizeof(state.messageBuf);
        char *pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, "[ origpid=");
        pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
        pos = ASSU::appendData(pos, end, ", pid=");
        pos = ASSU::appendInteger<pid_t, 10>(pos, end, getpid());
        pos = ASSU::appendData(pos, end, ", timestamp=");
        pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
        if (ctx->callCount == 2) {
            // This is the first time it crashed.
            pos = ASSU::appendData(pos, end, " ] Abort handler crashed! signo=");
            pos = appendSignalName(pos, end, state.signo);
            pos = ASSU::appendData(pos, end, ", reason=");
            pos = appendSignalReason(pos, end, state.info);
            pos = ASSU::appendData(pos, end, "\n");
            write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
            // Run default signal handler.
            raise(signo);
        } else {
            // This is the second time it crashed, meaning it failed to
            // invoke the default signal handler to abort the process!
            pos = ASSU::appendData(pos, end, " ] Abort handler crashed again! Force exiting this time. signo=");
            pos = appendSignalName(pos, end, state.signo);
            pos = ASSU::appendData(pos, end, ", reason=");
            pos = appendSignalReason(pos, end, state.info);
            pos = ASSU::appendData(pos, end, "\n");
            write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
            _exit(1);
        }
        return;
    }

    closeEmergencyPipes();

    {
        const char *end = state.messagePrefix + sizeof(state.messagePrefix);
        char *pos = state.messagePrefix;
        pos = ASSU::appendData(pos, end, "[ pid=");
        pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
        *pos = '\0';
    }

    /* We want to dump the entire crash log to both stderr and a log file.
     * We use 'tee' for this.
     */
    state.crashLogDir[0] = '\0';
    state.crashLogDirFd = -1;
    if (createCrashLogDir(state, t)) {
        forkAndRedirectToTeeAndMainLogFile(state.crashLogDir);
    }

    const char *end = state.messageBuf + sizeof(state.messageBuf);
    char *pos = state.messageBuf;
    // Print a \n just in case we're aborting in the middle of a non-terminated line.
    pos = ASSU::appendData(pos, end, "\n");
    pos = ASSU::appendData(pos, end, state.messagePrefix);
    pos = ASSU::appendData(pos, end, ", timestamp=");
    pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
    pos = ASSU::appendData(pos, end, " ] Process aborted! signo=");
    pos = appendSignalName(pos, end, state.signo);
    pos = ASSU::appendData(pos, end, ", reason=");
    pos = appendSignalReason(pos, end, state.info);
    pos = ASSU::appendData(pos, end, ", randomSeed=");
    pos = ASSU::appendInteger<unsigned int, 10>(pos, end, ctx->config->randomSeed);
    pos = ASSU::appendData(pos, end, "\n");
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    pos = state.messageBuf;
    if (state.crashLogDir[0] != '\0') {
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Crash log files will be dumped to ");
        pos = ASSU::appendData(pos, end, state.crashLogDir);
        pos = ASSU::appendData(pos, end, " <--- ******* LOOK HERE FOR DETAILS!!! *******\n");
    } else {
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Could not create crash log directory, so dumping to stderr only.\n");
    }
    write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    if (ctx->config->beep) {
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] PASSENGER_BEEP_ON_ABORT on, executing beep...\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

        child = asyncFork();
        if (child == 0) {
            closeAllFileDescriptors(2, true);
            #ifdef __APPLE__
                const char *command[] = { "osascript", NULL };
                execlp("osascript", "osascript", "-e", "beep 2", (char *) 0);
                printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
            #else
                const char *command[] = { "beep", NULL };
                execlp("beep", "beep", (char *) 0);
                printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
            #endif
            _exit(1);

        } else if (child == -1) {
            int e = errno;
            pos = state.messageBuf;
            pos = ASSU::appendData(pos, end, state.messagePrefix);
            pos = ASSU::appendData(pos, end, " ] Could fork a child process for invoking a beep: fork() failed with errno=");
            pos = ASSU::appendInteger<int, 10>(pos, end, e);
            pos = ASSU::appendData(pos, end, "\n");
            write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        }
    }

    if (ctx->config->stopProcess) {
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] PASSENGER_STOP_ON_ABORT on, so process stopped. Send SIGCONT when you want to continue.\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
        raise(SIGSTOP);
    }

    // It isn't safe to call any waiting functions in this signal handler,
    // not even read() and waitpid() even though they're async signal safe.
    // So we fork a child process and let it dump as much diagnostics as possible
    // instead of doing it in this process.
    child = asyncFork();
    if (child == 0) {
        // Sleep for a short while to allow the parent process to raise SIGSTOP.
        // usleep() and nanosleep() aren't async signal safe so we use select()
        // instead.
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = 100000;
        select(0, NULL, NULL, NULL, &tv);

        resetSignalHandlersAndMask();

        child = asyncFork();
        if (child == 0) {
            // OS X: for some reason the SIGPIPE handler may be reset to default after forking.
            // Later in this program we're going to pipe backtrace_symbols_fd() into the backtrace
            // sanitizer, which may fail, and we don't want the diagnostics process to crash
            // with SIGPIPE as a result, so we ignore SIGPIPE again.
            ignoreSigpipe();
            dumpDiagnostics(state);
            // The child process may or may or may not resume the original process.
            // We do it ourselves just to be sure.
            kill(state.pid, SIGCONT);
            _exit(0);

        } else if (child == -1) {
            int e = errno;
            pos = state.messageBuf;
            pos = ASSU::appendData(pos, end, state.messagePrefix);
            pos = ASSU::appendData(pos, end, "] Could not fork a child process for dumping diagnostics: fork() failed with errno=");
            pos = ASSU::appendInteger<int, 10>(pos, end, e);
            pos = ASSU::appendData(pos, end, "\n");
            write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
            _exit(1);

        } else {
            // Exit immediately so that child process is adopted by init process.
            _exit(0);
        }

    } else if (child == -1) {
        int e = errno;
        pos = state.messageBuf;
        pos = ASSU::appendData(pos, end, state.messagePrefix);
        pos = ASSU::appendData(pos, end, " ] Could not fork a child process for dumping diagnostics: fork() failed with errno=");
        pos = ASSU::appendInteger<int, 10>(pos, end, e);
        pos = ASSU::appendData(pos, end, "\n");
        write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);

    } else {
        raise(SIGSTOP);
        // Will continue after the child process has done its job.
    }

    // Run default signal handler.
    raise(signo);
}

void
installAbortHandler(const AbortHandlerConfig *config) {
    ctx = new AbortHandlerContext();
    memset(ctx, 0, sizeof(AbortHandlerContext));

    ctx->config = config;
    ctx->backtraceSanitizerPassProgramInfo = true;
    ctx->randomTokens = strdup(RandomGenerator().generateAsciiString(
        MAX_RANDOM_TOKENS * RANDOM_TOKEN_SIZE).c_str());
    ctx->emergencyPipe1[0] = -1;
    ctx->emergencyPipe1[1] = -1;
    ctx->emergencyPipe2[0] = -1;
    ctx->emergencyPipe2[1] = -1;

    abortHandlerConfigChanged();

    IGNORE_SYSCALL_RESULT(pipe(ctx->emergencyPipe1));
    IGNORE_SYSCALL_RESULT(pipe(ctx->emergencyPipe2));

    size_t alternativeStackSize = MINSIGSTKSZ + 128 * 1024;
    ctx->alternativeStack = (char *) malloc(alternativeStackSize);
    if (ctx->alternativeStack == NULL) {
        fprintf(stderr, "Cannot allocate an alternative stack with a size of %lu bytes!\n",
            (unsigned long) alternativeStackSize);
        fflush(stderr);
        abort();
    }

    stack_t stack;
    stack.ss_sp = ctx->alternativeStack;
    stack.ss_size = alternativeStackSize;
    stack.ss_flags = 0;
    if (sigaltstack(&stack, NULL) != 0) {
        int e = errno;
        fprintf(stderr, "Cannot install an alternative stack for use in signal handlers: %s (%d)\n",
            strerror(e), e);
        fflush(stderr);
        abort();
    }

    struct sigaction action;
    action.sa_sigaction = abortHandler;
    action.sa_flags = SA_RESETHAND | SA_SIGINFO;
    sigemptyset(&action.sa_mask);
    sigaction(SIGABRT, &action, NULL);
    sigaction(SIGSEGV, &action, NULL);
    sigaction(SIGBUS, &action, NULL);
    sigaction(SIGFPE, &action, NULL);
    sigaction(SIGILL, &action, NULL);
}

bool
abortHandlerInstalled() {
    return ctx != NULL;
}

void
abortHandlerLogFds() {
    if (ctx->emergencyPipe1[0] != -1) {
        P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe1[0], __FILE__, __LINE__,
            "Emergency pipe 1-0");
        P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe1[1], __FILE__, __LINE__,
            "Emergency pipe 1-1");
    }
    if (ctx->emergencyPipe2[0] != -1) {
        P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe2[0], __FILE__, __LINE__,
            "Emergency pipe 2-0");
        P_LOG_FILE_DESCRIPTOR_OPEN4(ctx->emergencyPipe2[1], __FILE__, __LINE__,
            "Emergency pipe 2-1");
    }
}

static void
useCxxFiltAsBacktraceSanitizer() {
    ctx->backtraceSanitizerCommand = strdup("c++filt -n");
    ctx->backtraceSanitizerPassProgramInfo = false;
}

void
abortHandlerConfigChanged() {
    const AbortHandlerConfig *config = ctx->config;
    char *oldInstallSpec = ctx->installSpec;
    char *oldRubyLibDir = ctx->rubyLibDir;
    char *oldTmpDir = ctx->tmpDir;
    char *oldCrashWatchCommand = ctx->crashWatchCommand;
    char *oldBacktraceSanitizerCommand = ctx->backtraceSanitizerCommand;

    if (config->resourceLocator != NULL) {
        string path;
        const ResourceLocator *locator = config->resourceLocator;

        ctx->installSpec = strdup(locator->getInstallSpec().c_str());
        ctx->rubyLibDir = strdup(locator->getRubyLibDir().c_str());
        ctx->tmpDir = strdup(getSystemTempDir());

        path = locator->getHelperScriptsDir() + "/crash-watch.rb";
        ctx->crashWatchCommand = strdup(path.c_str());

        if (ctx->installSpec == NULL || ctx->rubyLibDir == NULL
            || ctx->tmpDir == NULL || ctx->crashWatchCommand == NULL)
        {
            fprintf(stderr, "Cannot allocate memory for abort handler!\n");
            fflush(stderr);
            abort();
        }

        #ifdef __linux__
            path = StaticString(config->ruby) + " \""
                + locator->getHelperScriptsDir() +
                "/backtrace-sanitizer.rb\"";
            ctx->backtraceSanitizerCommand = strdup(path.c_str());
            ctx->backtraceSanitizerPassProgramInfo = true;
            if (ctx->backtraceSanitizerCommand == NULL) {
                fprintf(stderr, "Cannot allocate memory for abort handler!\n");
                fflush(stderr);
                abort();
            }
        #else
            useCxxFiltAsBacktraceSanitizer();
        #endif
    } else {
        ctx->installSpec = NULL;
        ctx->rubyLibDir = NULL;
        ctx->tmpDir = NULL;
        ctx->crashWatchCommand = NULL;
        useCxxFiltAsBacktraceSanitizer();
    }

    free(oldInstallSpec);
    free(oldRubyLibDir);
    free(oldTmpDir);
    free(oldCrashWatchCommand);
    free(oldBacktraceSanitizerCommand);
}

void
shutdownAbortHandler() {
    free(ctx->installSpec);
    free(ctx->rubyLibDir);
    free(ctx->tmpDir);
    free(ctx->crashWatchCommand);
    free(ctx->backtraceSanitizerCommand);
    free(ctx->randomTokens);
    free(ctx->alternativeStack);
    closeEmergencyPipes();
    delete ctx;
    ctx = NULL;
}


} // namespace Fundamentals
} // namespace Agent
} // namespace Passenger


/*
 * Override assert() to add more features and to fix bugs. We save the information
 * of the last assertion failure in a global variable so that we can print it
 * to the crash diagnostics report.
 */
#if defined(__GLIBC__)
    extern "C" __attribute__ ((__noreturn__))
    void
    __assert_fail(__const char *__assertion, __const char *__file,
        unsigned int __line, __const char *__function)
    {
        using namespace Passenger;

        LoggingKit::lastAssertionFailure.filename = __file;
        LoggingKit::lastAssertionFailure.line = __line;
        LoggingKit::lastAssertionFailure.function = __function;
        LoggingKit::lastAssertionFailure.expression = __assertion;
        fprintf(stderr, "Assertion failed! %s:%u: %s: %s\n", __file, __line, __function, __assertion);
        fflush(stderr);
        abort();
    }

#elif defined(__APPLE__)
    /* On OS X, raise() and abort() unfortunately send SIGABRT to the main thread,
     * causing the original backtrace to be lost in the signal handler.
     * We work around this for anything in the same linkage unit by just definin
     * our own versions of the assert handler and abort.
     */

    #include <pthread.h>

    extern "C" int
    raise(int sig) {
        return pthread_kill(pthread_self(), sig);
    }

    extern "C" void
    __assert_rtn(const char *func, const char *file, int line, const char *expr) {
        using namespace Passenger;

        LoggingKit::lastAssertionFailure.filename = file;
        LoggingKit::lastAssertionFailure.line = line;
        LoggingKit::lastAssertionFailure.function = func;
        LoggingKit::lastAssertionFailure.expression = expr;
        if (func) {
            fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n",
                expr, func, file, line);
        } else {
            fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n",
                expr, file, line);
        }
        fflush(stderr);
        abort();
    }

    extern "C" void
    abort() {
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set, SIGABRT);
        pthread_sigmask(SIG_UNBLOCK, &set, NULL);
        raise(SIGABRT);
        usleep(1000);
        __builtin_trap();
    }
#endif /* __APPLE__ */

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.0 [PHP 7 Update] [25.02.2019] maintained by KaizenLouie | C99Shell Github | Generation time: 0.0285 ]--