12

セグメンテーション違反を引き起こすコードがあるとしましょう。

char * ptr = NULL;
*ptr = "hello"; /* this will cause a segmentation fault */

実行時に出力する方法、セグメンテーション違反が発生したメモリ内のアドレス、およびセグメンテーション違反の理由 (禁止されたメモリ領域へのアクセスなど)。

コア ダンプ ファイルについて読みましたが、それが正しい解決策かどうかわかりません。

これどうやってするの?

PS、私は gdb または他のデバッガーを使用してそれを達成できることを認識していますが、目的はコードを使用してこれを行うことであり、コードのみです。

4

2 に答える 2

5

原因を知りたい場合は、次のようなシグナル ハンドラを登録できます。

void handler(int signum, siginfo_t *info, void *context)
{
  struct sigaction action = {
    .sa_handler = SIG_DFL,
    .sa_sigaction = NULL,
    .sa_mask = 0,
    .sa_flags = 0,
    .sa_restorer = NULL
  };

  fprintf(stderr, "Fault address: %p\n", info->si_addr);
  switch (info->si_code) {
  case SEGV_MAPERR:
    fprintf(stderr, "Address not mapped.\n");
    break;

  case SEGV_ACCERR:
    fprintf(stderr, "Access to this address is not allowed.\n");
    break;

  default:
    fprintf(stderr, "Unknown reason.\n");
    break;
  }

  /* unregister and let the default action occur */
  sigaction(SIGSEGV, &action, NULL);
}

そして、それを登録する必要がある場所:

  struct sigaction action = {
    .sa_handler = NULL,
    .sa_sigaction = handler,
    .sa_mask = 0,
    .sa_flags = SA_SIGINFO,
    .sa_restorer = NULL
  };


  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    perror("sigaction");
  }

基本的に、SIGSEGV が配信されたときに発火するシグナルを登録し、追加情報を取得して、man ページを引用します。

   The following values can be placed in si_code for a SIGSEGV signal:

       SEGV_MAPERR    address not mapped to object

       SEGV_ACCERR    invalid permissions for mapped object

これらは、セグ フォールトが発生する 2 つの基本的な理由に対応しています。つまり、アクセスしたページがまったくマップされていないか、そのページに対して試行した操作を実行できませんでした。

ここでは、シグナル ハンドラーが起動した後、それ自体を登録解除し、既定のアクションを置き換えます。これにより、失敗した操作が再度実行されるため、通常のルートでキャッチできます。これは、ページ フォールト (セグ フォールトを取得する前兆) の通常の動作であるため、デマンド ページングなどが機能します。

于 2013-04-15T14:59:57.890 に答える