Changeset 0d2cd10 for unix.c


Ignore:
Timestamp:
2018-03-26T16:48:32Z (6 years ago)
Author:
dequis <dx@…>
Branches:
master
Children:
230f6f1
Parents:
e1e5bd6
git-author:
dequis <dx@…> (26-03-18 16:26:56)
git-committer:
dequis <dx@…> (26-03-18 16:48:32)
Message:

Write backtrace to /var/lib/bitlbee/crash.log on SIGSEGV

Async-signal-safe code is very restricted (nothing that may call malloc
indirectly), so this code tries its best to show meaningful stuff, but
the output is still fairly raw. The contents of the log file are:

  • BITLBEE_VERSION, BITLBEE_CONFIGURE_ARGS
  • Backtrace as generated by backtrace()/backtrace_symbols_fd()
  • A small help text explaining how to get more useful symbol names
  • Memory maps (/proc/self/maps), which also mentions loaded plugins

The backtrace() function is a GNU extension, /proc/ is a linux thing.
Non-glibc platforms (such as musl) won't show anything, non-linux
platforms will skip the memory maps when /proc/self/maps fails to open.

I'd like to include timestamps, but I can't find a safe way to format
them. Even turning raw unix timestamps to strings is hard. Fun stuff.

I used the config directory because it's the only place we can be sure
we can write to. The filename is hardcoded for the same reason there are
no timestamps.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • unix.c

    re1e5bd6 r0d2cd10  
    4646#endif
    4747
     48#ifdef HAVE_BACKTRACE
     49#include <execinfo.h>
     50#endif
     51
    4852global_t global;        /* Against global namespace pollution */
    4953
     
    6367        char *old_cwd = NULL;
    6468        struct sigaction sig, old;
     69#ifdef HAVE_BACKTRACE
     70        void *unused[1];
     71#endif
    6572
    6673        /* Required to make iconv to ASCII//TRANSLIT work. This makes BitlBee
     
    175182        sigaction(SIGINT, &sig, &old);
    176183        sigaction(SIGTERM, &sig, &old);
     184
     185#ifdef HAVE_BACKTRACE
     186        /* As per the backtrace(3) man page, call this outside of the signal
     187         * handler once to ensure any dynamic libraries are loaded in an
     188         * async-signal-safe environment to prevent deadlocks */
     189        backtrace(unused, 1);
     190#endif
    177191
    178192        if (!getuid() || !geteuid()) {
     
    292306}
    293307
     308#ifdef HAVE_BACKTRACE
     309/* Writes a backtrace to (usually) /var/lib/bitlbee/crash.log
     310 * No malloc allowed means not a lot can be written to that file */
     311static void sighandler_crash_backtrace()
     312{
     313        int fd, mapsfd;
     314        int size;
     315        void *trace[128];
     316        const char message[] = "## " PACKAGE " crashed\n"
     317                "## Version: " BITLBEE_VERSION "\n"
     318                "## Configure args: " BITLBEE_CONFIGURE_ARGS "\n"
     319                "##\n"
     320                "## Backtrace:\n\n";
     321        const char message2[] = "\n"
     322                "## Hint: To get details on addresses use\n"
     323                "##   addr2line -e <binary> <address>\n"
     324                "## or\n"
     325                "##   gdb <binary> -ex 'l *<address>' -ex q\n"
     326                "## where <binary> is a filename from above and <address> is the part between (...)\n"
     327                "##\n\n";
     328        const char message3[] = "\n## End of memory maps. See above for the backtrace\n\n";
     329
     330        fd = open(CRASHFILE, O_WRONLY | O_APPEND | O_CREAT, 0600);
     331
     332        if (fd == -1 || write(fd, message, sizeof(message) - 1) == -1) {
     333                return;
     334        }
     335
     336        size = backtrace(trace, 128);
     337        backtrace_symbols_fd(trace, size, fd);
     338
     339        (void) write(fd, message2, sizeof(message2) - 1);
     340
     341        /* a bit too linux-specific, so fail gracefully */
     342        mapsfd = open("/proc/self/maps", O_RDONLY, 0);
     343
     344        if (mapsfd != -1) {
     345                char buf[4096] = {0};
     346                ssize_t bytes;
     347
     348                while ((bytes = read(mapsfd, buf, sizeof(buf))) > 0) {
     349                        (void) write(fd, buf, bytes);
     350                }
     351                (void) close(mapsfd);
     352                (void) write(fd, message3, sizeof(message3) - 1);
     353        }
     354
     355        (void) close(fd);
     356}
     357#endif
     358
    294359/* Signal handler for SIGSEGV
    295360 * A desperate attempt to tell the user that everything is wrong in the world.
     
    298363{
    299364        GSList *l;
    300         int unused G_GNUC_UNUSED;
    301         const char *message = "ERROR :BitlBee crashed! (SIGSEGV received)\r\n";
    302         int len = strlen(message);
     365        const char message[] = "ERROR :BitlBee crashed! (SIGSEGV received)\r\n"
     366#ifdef HAVE_BACKTRACE
     367                "ERROR :Writing backtrace to " CRASHFILE "\r\n"
     368#endif
     369                "ERROR :This is a bug either in BitlBee or a plugin, ask us on IRC if unsure\r\n";
    303370
    304371        for (l = irc_connection_list; l; l = l->next) {
     
    306373                sock_make_blocking(irc->fd);
    307374                if (irc->sendbuffer) {
    308                         unused = write(irc->fd, irc->sendbuffer, strlen(irc->sendbuffer));
    309                 }
    310                 unused = write(irc->fd, message, len);
    311         }
     375                        (void) write(irc->fd, irc->sendbuffer, strlen(irc->sendbuffer));
     376                }
     377                (void) write(irc->fd, message, sizeof(message) - 1);
     378        }
     379
     380#ifdef HAVE_BACKTRACE
     381        sighandler_crash_backtrace();
     382#endif
    312383
    313384        raise(signal);
Note: See TracChangeset for help on using the changeset viewer.