2012-12-12 107 views
0

我要趕SIGBUS,我的代碼如下所示:捕捉SIGBUS和C++

#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

看到這個:http://stackoverflow.com/questions/12139609 /爲什麼不輸出控制檯上的信號處理 –

+2

您不能從信號處理程序調用'printf',也不能使用信號處理程序中的'cout'。如果一個函數使用'printf'或'cout'被一個信號中斷?另外,[你不能從信號處理程序調用'exit'](http://bytes.com/topic/c/answers/440109-signal-handler-sigsegv)。 –

+0

我測試了它,並且與printf一起工作 – thanhtv

回答

2

您不能在信號處理程序中使用printfcout。你也不能撥打exitprintf這次幸運,但cout沒有那麼幸運。如果你的程序處於不同的狀態,那麼cout可以工作,printf不會。或者可能兩者都不兼容。檢查操作系統的文檔以查看哪些功能是信號安全的(如果存在,通常記錄非常糟糕)。

你在這種情況下,最安全的辦法就是直接打電話給writeSTDERR_FILENO然後調用_exit(不exit,一個是在信號處理不安全的)。在某些系統上,可以安全地撥打fprintfstderr,但我不確定glibc是否是其中之一。

編輯:要回答您添加的問題,您需要使用sigaction設置您的信號處理程序以獲取附加信息。這個例子就像我在一個信號處理程序中一樣,如果你想要進步的話,我會包含一個替代方法。請注意,寫在理論上是不安全的,因爲它會破壞錯誤號,但由於我們正在做_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

根據您的意見,你要調試SIGBUS,並且已經有存在的問題有關: Debugging SIGBUS on x86 Linux

,列出了一些可能的原因。但是可能SIGBUS最可能的原因是,你有內存損壞,並且它會混亂,所以你稍後會得到SIGBUS ...所以調試信號可能不會有助於確定錯誤。這就是說,使用調試器來捕獲信號被拋出的代碼中的點,並查看它是否是指針。這是找出原因的一個很好的起點。