4

このタイプのプログラミングは初めてなので、質問が些細なことでしたら申し訳ありません。私がやろうとしているのは、プログラムでセグメンテーション違反を引き起こし、プログラムを終了する代わりに、信号を処理してセグメンテーション違反後に実行を継続したいということです。動作しているように見えるコードを書きましたが、これがこれを行う方法であることを確認したいだけです。だからここに私のコードがあります。

void myhandle(int mysignal, siginfo_t *si, void* arg)
{
  printf("Signal is %d\n",mysignal);

  ucontext_t *context = (ucontext_t *)arg;
  context->uc_mcontext.gregs[REG_RIP]++;
}


int main(int argc, char *argv[])
{
   struct sigaction action;

  action.sa_handler=myhandle;
  sigaction(11,&action,NULL);

  printf("Before segfault\n");

  int *a=NULL;
  int b=*a;

  printf("I am still alive\n");

  return 0;
}

myhandle 内の printf が 2 回実行される理由を説明してもらえますか? また、このコードは大丈夫ですか?

ありがとうございました。

4

5 に答える 5

2

ジャンプする PC (つまり RIP) を見つけるために、dissamembly をチェックする必要があるかもしれません。あなたの場合、次のようになります。

    int *a=NULL;
  400697:       48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
  40069e:       00
    int b=*a;
  40069f:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4006a3:       8b 00                   mov    (%rax),%eax
  4006a5:       89 45 f4                mov    %eax,-0xc(%rbp)

    printf("I am still alive\n");
  4006a8:       bf 7c 07 40 00          mov    $0x40077c,%edi
  4006ad:       e8 de fd ff ff          callq  400490 <puts@plt>

、および例外は 0x4006a3 にあります。printf() にジャンプするには、0x4006a8 に設定する必要があります。または +2 ~ 0x4006a5 も有効です。

メッセージが 2 回ダンプされる理由は、最初の呼び出し時に、

context->uc_mcontext.gregs[REG_RIP]++

、RIPを0x4006a4に設定し、1つの無効な場所が別の例外をトリガーします。

于 2016-01-25T06:11:52.167 に答える
1

myhandle 内の printf が 2 回実行される理由を説明してもらえますか?

動作は OS に依存しているようです。からの制御myhandleがまったく戻らない場合がありmainます。

シグナル 11 をキャッチするのは異常です。通常、これは OS によって処理されてプログラムを終了します。

ただし、シグナル ハンドラーを記述して、その関数にexit.

struct sigaction action;
struct sigaction old_action;

void myhandle( int mysignal )
{
    if( 11 == mysignal )
    {
        printf( "Signal is %d\n", mysignal );   // <-- this should print OK.
        sigaction( 11, &old_action, NULL );     // restore OS signal handler, or just exit().
        return;
    }
}


int main(int argc, char *argv[])
{
    action.sa_handler = myhandle;
    sigaction( 11, &action, &old_action );

    printf("Before segfault\n");

    int *a=NULL;
    int b=*a;

    printf( "I am still alive\n" );   // <-- this won't happen
    return 0;
}
于 2016-01-25T06:11:28.003 に答える
0

これが言われているかどうかはわかりませんが、malloc() を使用しているため、シグナルハンドラから printf() を呼び出すのは安全ではありません。

シグナル処理コンテキストでどの関数が安全かを理解するために、もっと読んでください。Linux および BSD/MacOS では、別の方法として、特別なファイル記述子でシグナル配信を手配することができます。Linux では、signalfd 関数ファミリーを介してこれを行い、通常のイベント ループでシグナルを処理できます。

Linux に関する Michael Kerrisk の本は、ここでの素晴らしいリファレンスです。

于 2022-02-11T16:29:21.770 に答える