1

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

4

2 に答える 2

3

printforcoutをシグナル ハンドラで使用することはできません。に電話することもできませんexitprintf今回は運が良かったが、 は運が悪かったcout。プログラムが別の状態にある場合は、動作する場合coutと動作しprintfない場合があります。または、どちらでもない、または両方かもしれません。オペレーティング システムのドキュメントを調べて、どの関数がシグナル セーフであるかを確認してください (存在する場合、多くの場合、ドキュメントが非常に不適切です)。

この場合の最も安全な方法は、writeSTDERR_FILENO直接呼び出してから呼び出すことです_exit( ではなくexit、シグナル ハンドラーでは安全ではありません)。一部のシステムでは を安全に呼び出すfprintfことstderrができますが、glibc がそれらの 1 つであるかどうかはわかりません。

編集:追加された質問に答えるには、シグナルハンドラを設定して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;
}
于 2012-12-12T08:19:04.623 に答える
1

あなたのコメントによると、あなたは SIGBUS をデバッグしようとしていますが、それについては既に質問があります: Debugging SIGBUS on x86 Linux

これには、いくつかの考えられる原因がリストされています。しかし、おそらくSIGBUSの最も可能性の高い理由は、メモリが破損していて、それが混乱して後でSIGBUSを取得することです...したがって、シグナルをデバッグしてもバグを特定するのに役立たない場合があります。そうは言っても、デバッガーを使用して、シグナルがスローされたコード内のポイントをキャッチし、それがポインターであるかどうかを確認します。これは、原因を突き止めるための良い出発点です。

于 2012-12-12T08:18:38.953 に答える