c++ - 在 C 和 C++ 中捕获 SIGBUS

标签 c++ c sigbus

我想捕捉SIGBUS,我的代码如下所示:

#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;
}

当我使用printf时,它可以通过调用catch_sigbus来捕获,但是当我使用cout时,它不能。那么有人可以帮助我吗?我在 Ubuntu 12.04 上运行。

我还有一个问题。当我捕获SIGBUS时,如何获取si_code? BUS_ADRALN/BUS_ADRERR/BUS_OBJERR

最佳答案

您不能在信号处理程序中使用 printfcout。您也不能调用 exit。这次您对 printf 很幸运,但对 cout 就没那么幸运了。如果您的程序处于不同的状态,则 cout 可能会工作,而 printf 则不会。或者两者都不是,或者两者都有。检查操作系统的文档,看看哪些函数是信号安全的(如果存在,则通常记录得很糟糕)。

在这种情况下,最安全的选择是直接调用 writeSTDERR_FILENO,然后调用 _exit (而不是 exit >,这个在信号处理程序中是不安全的)。在某些系统上,调用 fprintfstderr 是安全的,但我不确定 glibc 是否是其中之一。

编辑:要回答您添加的问题,您需要使用 sigaction 设置信号处理程序以获取附加信息。这个示例是我在信号处理程序中进行的,如果您想进一步了解,我还提供了一种替代方法。请注意,理论上 write 是不安全的,因为它会破坏 errno,但由于我们正在执行 _exit,因此在这种特殊情况下它将是安全的:

#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;
}

关于c++ - 在 C 和 C++ 中捕获 SIGBUS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13834643/

相关文章:

c++ - 使用基类指针作为方法的参数

c++ - 如何将 const char* 转换为 char*

ios - 从 iOS Xcode 5 中的数组列表中一一显示字符串

c - 如何找到 RB 树中的最大值

iOS 应用程序在设备上的发布版本中崩溃

c++ - NPAPI:需要 RetainObject() 两次处理程序,否则 SIGBUS

linux - nanosleep() 系统调用因总线错误而醒来?

c++ - 如何在 for 循环中声明第二个迭代器?

c++ - 运算符(==)重载错误

c++ - 表达式 -2[array] 是如何工作的?