我想抓住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
答案 0 :(得分:2)
您不能在信号处理程序中使用printf
或cout
。你也不能打exit
。这次你很幸运printf
,但你对cout
没有那么幸运。如果您的计划处于不同的状态,则cout
可能会有效,而printf
则不会。或者两者兼而有之。检查操作系统的文档,看看哪些功能是信号安全的(如果存在,通常记录非常严重)。
在这种情况下,您最安全的选择是直接致电write
至STDERR_FILENO
,然后致电_exit
(而不是exit
,在信号处理程序中不安全)。在某些系统上,将fprintf
调用stderr
是安全的,但我不确定glibc是否是其中之一。
编辑:要回答添加的问题,您需要使用sigaction
设置信号处理程序以获取其他信息。这个例子就在我进入信号处理程序的范围内,如果你想要进步,我会提供另一种方法。请注意,写入在理论上是不安全的,因为它会破坏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;
}
答案 1 :(得分:1)
根据您的评论,您正在尝试调试SIGBUS,并且已经存在这样的问题: Debugging SIGBUS on x86 Linux
列出了许多可能的原因。但可能是SIGBUS最可能的原因是,你有内存损坏而且会让事情变得混乱,所以你以后会得到SIGBUS ......所以调试信号可能对确定bug没有帮助。话虽这么说,使用调试器来捕获抛出信号的代码点,看看它是否是一个指针。这是尝试找出原因的良好起点。