1

I want to catch SIGBUS, my code is shown below:

#include <stdlib.h>
#include <signal.h>
#include <iostream>
#include <stdio.h>

void catch_sigbus (int sig)
{
    //std::cout << "SIGBUS" << std::endl;
    printf("SIGBUS\n");   
    exit(-1);
}


int main(int argc, char **argv) {

signal (SIGBUS, catch_sigbus);

    int *iptr;
    char *cptr;

#if defined(__GNUC__)
# if defined(__i386__)
    /* Enable Alignment Checking on x86 */
    __asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__) 
     /* Enable Alignment Checking on x86_64 */
    __asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

    /* malloc() always provides aligned memory */
    cptr = (char*)malloc(sizeof(int) + 1);

    /* Increment the pointer by one, making it misaligned */
    iptr = (int *) ++cptr;

    /* Dereference it as an int pointer, causing an unaligned access */

    *iptr = 42;

    return 0;
}

When I use printf, it can catch by calling catch_sigbus, but when I use cout, it cannot. So anybody could help me? I run on Ubuntu 12.04.

I have another question. When I catch SIGBUS, how can I get si_code? BUS_ADRALN/BUS_ADRERR/BUS_OBJERR

thanhtv
  • 323
  • 1
  • 4
  • 12
  • See this: http://stackoverflow.com/questions/12139609/why-no-output-on-console-on-signal-handling – Jeremy Friesner Dec 12 '12 at 07:15
  • 2
    You can't call `printf` from a signal handler, nor can you use `cout` from a signal handler. What if a function that uses `printf` or `cout` as interrupted by a signal? Also, [you can't call `exit` from a signal handler](http://bytes.com/topic/c/answers/440109-signal-handler-sigsegv). – David Schwartz Dec 12 '12 at 07:15
  • I tested and it worked with printf – thanhtv Dec 12 '12 at 07:29
  • Oh, I have already add `"\n"` at the end of `cout`, and it work! – thanhtv Dec 12 '12 at 07:35
  • You really can't do very much if you catch a SIGBUS except exit the program. You can't reliably return from the signal handler because the reason it was called is because the computation is in an indeterminate and irrecoverable state. – Jonathan Leffler Dec 12 '12 at 08:07
  • 1
    I want to debug, for checking why does my program get SIGBUS – thanhtv Dec 12 '12 at 08:12
  • 2
    @thanhtv: "I tested and it worked with printf" -- that's not good enough. Just because it works once does not mean it is safe. It is not safe to call `printf` in a signal handler. – Dietrich Epp Dec 12 '12 at 08:28
  • So, what should I do if I want to debug? – thanhtv Dec 12 '12 at 08:33
  • @thanhtv: Use GDB or Valgrind. – Dietrich Epp Dec 12 '12 at 09:10

2 Answers2

3

You can't use printf or cout in a signal handler. Nor can you call exit. You got lucky with printf this time, but you weren't as lucky with cout. If your program is in a different state maybe cout will work and printf won't. Or maybe neither, or both. Check the documentation of your operating system to see which functions are signal safe (if it exists, it's often very badly documented).

Your safest bet in this case is to call write to STDERR_FILENO directly and then call _exit (not exit, that one is unsafe in a signal handler). On some systems it's safe to call fprintf to stderr, but I'm not sure if glibc is one of them.

Edit: To answer your added question, you need to set up your signal handlers with sigaction to get the additional information. This example is as far as I'd go inside a signal handler, I included an alternative method if you want to go advanced. Notice that write is theoretically unsafe because it will break errno, but since we're doing _exit it will be safe in this particular case:

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

void
bus_handler(int sig, siginfo_t *si, void *vuctx)
{
        char buf[2];
#if 1
        /*                                                                                                                           
         * I happen to know that si_code can only be 1, 2 or 3 on this                                                               
         * particular system, so we only need to handle one digit.                                                                   
         */
        buf[0] = '0' + si->si_code;
        buf[1] = '\n';
        write(STDERR_FILENO, buf, sizeof(buf));
#else
        /*                                                                                                                           
         * This is a trick I sometimes use for debugging , this will                                                                 
         * be visible in strace while not messing with external state too                                                            
         * much except breaking errno.                                                                                                
         */
        write(-1, NULL, si->si_code);
#endif
        _exit(1);
}

int
main(int argc, char **argv)
{
        struct sigaction sa;
        char *cptr;
        int *iptr;

        memset(&sa, 0, sizeof(sa));

        sa.sa_sigaction = bus_handler;
        sa.sa_flags = SA_SIGINFO;
        sigfillset(&sa.sa_mask);
        sigaction(SIGBUS, &sa, NULL);

#if defined(__GNUC__)
# if defined(__i386__)
        /* Enable Alignment Checking on x86 */
        __asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
        /* Enable Alignment Checking on x86_64 */
        __asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

        /* malloc() always provides aligned memory */
        cptr = (char*)malloc(sizeof(int) + 1);

        /* Increment the pointer by one, making it misaligned */
        iptr = (int *) ++cptr;

        /* Dereference it as an int pointer, causing an unaligned access */

        *iptr = 42;

        return 0;
}
Art
  • 19,807
  • 1
  • 34
  • 60
1

According to your comment, you're trying to debug SIGBUS, and there's existing question about that already: Debugging SIGBUS on x86 Linux

That lists a number of possible causes. But probably the most likely reason for SIGBUS is, you have memory corruption and it messes things up so you get SIGBUS later... So debugging the signal might not be helpful at nailing the bug. That being said, use debugger to catch the point in code where signal is thrown, and see if it is a pointer. That's a good starting point for trying to find out the cause.

Community
  • 1
  • 1
hyde
  • 60,639
  • 21
  • 115
  • 176