c - 打印段错误原因

标签 c linux unix segmentation-fault

<分区>

假设我有一段代码会导致段错误。

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

如何在运行时打印发生段错误的内存地址,以及段错误的原因(访问禁止的内存区域,或其他)。

我阅读了核心转储文件,但我不确定它是否是正确的解决方案。

我该怎么做?

P.S,我知道我可以通过使用 gdb 或其他调试器来实现这一点,但目的是通过使用代码来实现这一点,而且只能使用代码。

最佳答案

如果你想知道原因,你可以注册一个信号处理程序,比如:

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 被传送时,你会得到一些额外的信息,引用手册页:

   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

这些映射到出现段错误的两个基本原因——要么您访问的页面根本没有映射,要么您不允许执行您尝试对该页面执行的任何操作。

在信号处理程序触发后,它会自行注销并替换默认操作。这会导致再次执行失败的操作,以便它可以被正常路由捕获。这是页面错误(出现段错误的前兆)的正常行为,因此请求分页之类的事情会起作用。

关于c - 打印段错误原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16015127/

相关文章:

c - 将排列后的字符串存储到数组中

c - 为什么看起来 INT_MIN 和 INT_MAX 超出了 int 类型的范围?

c - 图书馆包括哪些功能?

r - 在 debian 机器中使用 roll_lm 时出错

将 system() 调用执行的命令的输出复制到 char 数组

c - 如何接收 (void *)0x12345678 参数?

python - 使用 Cython 将 Python 链接到共享库

linux - 并行运行 shell 脚本

linux - 比较具有不同列号的两个文件,如果条件满足则将要求打印到新文件

c - 为什么在尝试从我的内核模块访问共享内存时得到 "Unhandled fault: imprecise external abort"?